3.9.0 Feature & Bugfix Release (#394)

* Update openid-connect-generic-client-wrapper.php

Add openid-connect-generic-session-expired action before to allow consumers to act on the refresh token expiration

* Implement singleton pattern for OpenID_Connect_Generic class

This will allow developers who want to be able to call methods belonging to this class (or methods belonging to any of this class's properties) to do so, without having to create a new instance, and therefore repeat all the bootstrapping.

Instead, they will just be able to call OpenID_Connect_Generic::instance() to retrieve the singleton.

* Add functions.php file for global functions

These will act as wrappers for methods you would otherwise call by getting the Open_ID_Connect_Generic singleton and then calling the appropriate method.

* Make client_wrapper a public property

This allows us to access client_wrapper methods via the singleton of Open_ID_Connect_Generic.

* Support aggregated claims (#254)

* use tabs instead of spaces

* added define config with OIDC_LOGIN_TYPE and OIDC_CLIENT_SCOPE

scopes are needed when logging in so this is a no-brainer and this
can be deployed using deployments

login type can be defined here when you want to enforce SSO from the
deployment.

* More define-driven settings

* fix linting

* fix code analysis errors

* fix more linting, add more exception handling

* Added the OIDC_CREATE_IF_DOES_NOT_EXIST define

* Added documentation and phpstan defines

* Added data in environment_settings

* Fixes QS not being added to the redirect URL

* fix #178
Update last-token-response user meta after refresh

* add a basic method to refresh user claim outside of this plugin

* fix return doc

* add a basic method to refresh user claim outside of this plugin

* fix return doc

* Revert "fix return doc"

This reverts commit e19d6f3ffd3f7684dd843408ec911c4b6d614328.

* Revert "add a basic method to refresh user claim outside of this plugin"

This reverts commit 1a5fa9b045c7b50a17dc3cfd5482fc33be9aa6ee.

* Initial Codepsaces Development Environment

* Adds Gitpod Support Alongside Codespaces Support

* Only load admin CSS when showing settings page

* Updates Development Environment for PHP & WordPress

- Updates local development environment to use a Composer Docker
  container.
- Updates VS Code/Codespaces devcontainer to bullseye/PHP 7.4.
- Updates VS Code/Codespaces devcontainer & GitPod starting commands.
- Updates build environment to use PHP 7.4 & Composer 2.
- Updates build environment Composer packages.
- Updates Composer WordPress install to use the johnpbloch packages.

* Fixes Running PHPStan in Docker & Static Analysis Issues

- Updates the PHP/Composer Docker image memory limit to
  allow PHPStand to run properly.
- Fixes static analysis issues reported by PHPStan.
- Updates PHPStan & extensions to latest versions.
- Updates PHPStan configuration for latest version.

* Update GitHub Actions for PHP/Composer/WordPress Changes

- Updates GitHub Actions to use Composer v2.
- Updates GitHub Actions to use PHP 7.4.
- Updates GitHub Actions to use WordPress 5.7 as stable.

* Updates WordPress Version Composer Dependencies

- Updates the installed WordPress version to 5.7.
- Updates the installed WordPress stubs version to 5.7.

* Fixes GitHub Actions for Composer 2 Changes

* Fixes GitHub Actions for PHP Unit testing

- Changes PHPUnit switch to dev-master for PHP 8.0.

* Updates GrumPHP & GrumPHP Unit Testing PHP 8 Support

- Updates GrumPHP to a newer version.
- Updates Unit Testing PHP 8.0 to use GrumPHP dev-master.

* Updates Unit Testing for PHPUnit Testing w/ PHP8

* Updates Unit Testing Composer Updates to Run w/ PHP 8

* Updates Composer PHPUnit for PHP 8 Override

* Multisite/network configurations use your current blog as the default when using the WP_User_Query which means if a user already exists, from a different blog, you will not find them, but also can't create a new account because they already exist.  This overrides your current blog and will search 'all'

* CodeSpaces Dev Container Updates & Composer Updates

* Updating GrumPHP & Composer Dependencies

* Updates NPM Modules & Changes Plugin Instance Visibility

* Updates @wordpress/scripts & ~wordpress/env to the latest versions.
* Changes the visibility of the plugin class instance attribute.

* Bump tar from 4.4.13 to 4.4.19

Bumps [tar](https://github.com/npm/node-tar) from 4.4.13 to 4.4.19.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v4.4.13...v4.4.19)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump hosted-git-info from 2.8.8 to 2.8.9

Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

---
updated-dependencies:
- dependency-name: hosted-git-info
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump lodash from 4.17.19 to 4.17.21

Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

---
updated-dependencies:
- dependency-name: lodash
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ssri from 6.0.1 to 6.0.2

Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: ssri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump path-parse from 1.0.6 to 1.0.7

Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ws from 6.2.1 to 6.2.2

Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/6.2.1...6.2.2)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* coding standards issues

* Fix wordpress coding standards issues

* Redone acr-values-support

acr-values support

* Fix code-standard errors

Fixed reported code-standard issues found

* Update openid-connect-generic-client.php

fixing code-indentment after report

* Update openid-connect-generic-client-wrapper.php

fix for reported code-standard errors

* Update openid-connect-generic-settings-page.php

Fixing code-standard reported errors

* Update openid-connect-generic-client.php

re-aligned line 225 ( indentment error)

* Refactors new ACR Handling Code for Better Code Quality

* Fixes some incorrect ACR handling code that incorrectly
  added the ACR when it wasn't set.
* Adds missing settings disable handling when ACR constant
  is set.
* Refactors code for simplicity and code quality.

* Fixes #243 Nickname from Claim Regression

* Fixes the regression caused by the code changes in 3.8.0
  which resulted in not performing proper fallbacks for
  missing cliams such as the nickname.
* Fixes invalid Node version in NVM configuration.

* Fixes Indentity Mapping & Creation Issues

* Fixes issues with improperly handling combinations of the
  "Link Existing Users", "Create user if does not exist", and
  "Identify with User Name" configuration options.
* Addresses issues related to case sensitivity of usernames
  when attempting to "Link Existing Users".
* Fixes typos and formatting on the plugin Settings screen.

* Dependabot Security Related Fixes & Refactoring

* Update to require Node v14 & NPM 6.14.15.
* Updates to Grunt 1.4.1.
* Forces resolution of dependencies for security fixes.
* Update @wordpress packages to their latest versions.
* Refactors the NPM & Composer scripts.

* Updates WP to Latest Dev Standard for Local Development

* Refactors Callable Refresh User Claims Function & Action

* Moves `openid-connect-generic-update-user-using-current-claim` action
  to within update user metadata during login.
* Adds a new publicly callable method that uses the plugin singleton.

* Prep for 3.9.0 Release

Co-authored-by: jkouris <35877237+jkouris@users.noreply.github.com>
Co-authored-by: Rob Skilling <rob@dxw.com>
Co-authored-by: Martin Schanzenbach <schanzen@gnunet.org>
Co-authored-by: Chloé "Matcha" Desoutter <chloe.desoutter@bluenove.com>
Co-authored-by: Martin <schanzen@users.noreply.github.com>
Co-authored-by: Sylwester Kardziejonek <sylwester.kardziejonek@gmail.com>
Co-authored-by: Nicolas Dhers <nicolas@rkcreation.fr>
Co-authored-by: Tom McCaffery <tom@weareadjacent.com>
Co-authored-by: Dan <dan@testinnovators.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: John Kouris <jkouris@everyincome.com>
Co-authored-by: Glowsome <administrator@comsolve.nl>
isekai^2
Tim Nolte 3 years ago committed by GitHub
parent a283a18fec
commit d4f0f4b51f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,47 @@
# Note: You can use any Debian/Ubuntu based image you want.
FROM mcr.microsoft.com/vscode/devcontainers/base:bullseye
# [Option] Install zsh
ARG INSTALL_ZSH="true"
# [Option] Upgrade OS packages to their latest versions
ARG UPGRADE_PACKAGES="false"
# [Option] Enable non-root Docker access in container
ARG ENABLE_NONROOT_DOCKER="true"
# [Option] Use the OSS Moby Engine instead of the licensed Docker Engine
ARG USE_MOBY="true"
# Install needed packages and setup non-root user. Use a separate RUN statement to add your
# own dependencies. A user of "automatic" attempts to reuse an user ID if one already exists.
ARG USERNAME=automatic
ARG USER_UID=1000
ARG USER_GID=$USER_UID
COPY library-scripts/*.sh /tmp/library-scripts/
RUN apt-get update \
&& /bin/bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \
# Use Docker script from script library to set things up
&& /bin/bash /tmp/library-scripts/docker-in-docker-debian.sh "${ENABLE_NONROOT_DOCKER}" "${USERNAME}" "${USE_MOBY}" \
# Clean up
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts/
VOLUME [ "/var/lib/docker" ]
# Setting the ENTRYPOINT to docker-init.sh will start up the Docker Engine
# inside the container "overrideCommand": false is set in devcontainer.json.
# The script will also execute CMD if you need to alter startup behaviors.
ENTRYPOINT [ "/usr/local/share/docker-init.sh" ]
CMD [ "sleep", "infinity" ]
# [Optional] Uncomment this section to install additional OS packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install php7.4-cli php7.4-curl php7.4-dom php7.4-intl php7.4-json php7.4-mbstring php7.4-xml
# Install Composer.
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
# nvm environment variables
# ENV NVM_DIR /usr/local/nvm
ENV NODE_VERSION 12
# Install Node Version Manager(NVM).
RUN su vscode -c "curl --silent -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash"

@ -0,0 +1,29 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/docker-in-docker
{
"name": "Docker in Docker",
"dockerFile": "Dockerfile",
"runArgs": ["--init", "--privileged"],
"mounts": ["source=dind-var-lib-docker,target=/var/lib/docker,type=volume"],
"overrideCommand": false,
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-azuretools.vscode-docker"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm run setup",
// Use 'postStartCommand' to run commands after the container has started.
"postStartCommand": "npm start -- --update",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}

@ -0,0 +1,478 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md
# Maintainer: The VS Code and Codespaces Teams
#
# Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag] [install Oh My Zsh! flag] [Add non-free packages]
set -e
INSTALL_ZSH=${1:-"true"}
USERNAME=${2:-"automatic"}
USER_UID=${3:-"automatic"}
USER_GID=${4:-"automatic"}
UPGRADE_PACKAGES=${5:-"true"}
INSTALL_OH_MYS=${6:-"true"}
ADD_NON_FREE_PACKAGES=${7:-"false"}
SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)"
MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
if [ "$(id -u)" -ne 0 ]; then
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
rm -f /etc/profile.d/00-restore-env.sh
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
chmod +x /etc/profile.d/00-restore-env.sh
# If in automatic mode, determine if a user already exists, if not use vscode
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
USERNAME=""
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
USERNAME=${CURRENT_USER}
break
fi
done
if [ "${USERNAME}" = "" ]; then
USERNAME=vscode
fi
elif [ "${USERNAME}" = "none" ]; then
USERNAME=root
USER_UID=0
USER_GID=0
fi
# Load markers to see which steps have already run
if [ -f "${MARKER_FILE}" ]; then
echo "Marker file found:"
cat "${MARKER_FILE}"
source "${MARKER_FILE}"
fi
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
# Function to call apt-get if needed
apt_get_update_if_needed()
{
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}
# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
package_list="apt-utils \
openssh-client \
gnupg2 \
iproute2 \
procps \
lsof \
htop \
net-tools \
psmisc \
curl \
wget \
rsync \
ca-certificates \
unzip \
zip \
nano \
vim-tiny \
less \
jq \
lsb-release \
apt-transport-https \
dialog \
libc6 \
libgcc1 \
libkrb5-3 \
libgssapi-krb5-2 \
libicu[0-9][0-9] \
liblttng-ust0 \
libstdc++6 \
zlib1g \
locales \
sudo \
ncdu \
man-db \
strace \
manpages \
manpages-dev \
init-system-helpers"
# Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian
if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then
# Bring in variables from /etc/os-release like VERSION_CODENAME
. /etc/os-release
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
echo "Running apt-get update..."
apt-get update
package_list="${package_list} manpages-posix manpages-posix-dev"
else
apt_get_update_if_needed
fi
# Install libssl1.1 if available
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
package_list="${package_list} libssl1.1"
fi
# Install appropriate version of libssl1.0.x if available
libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
# Debian 9
package_list="${package_list} libssl1.0.2"
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
# Ubuntu 18.04, 16.04, earlier
package_list="${package_list} libssl1.0.0"
fi
fi
echo "Packages to verify are installed: ${package_list}"
apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
# Install git if not already installed (may be more recent than distro version)
if ! type git > /dev/null 2>&1; then
apt-get -y install --no-install-recommends git
fi
PACKAGES_ALREADY_INSTALLED="true"
fi
# Get to latest versions of all packages
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
apt_get_update_if_needed
apt-get -y upgrade --no-install-recommends
apt-get autoremove -y
fi
# Ensure at least the en_US.UTF-8 UTF-8 locale is available.
# Common need for both applications and things like the agnoster ZSH theme.
if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
LOCALE_ALREADY_SET="true"
fi
# Create or update a non-root user to match UID/GID.
if id -u ${USERNAME} > /dev/null 2>&1; then
# User exists, update if needed
if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -G $USERNAME)" ]; then
groupmod --gid $USER_GID $USERNAME
usermod --gid $USER_GID $USERNAME
fi
if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then
usermod --uid $USER_UID $USERNAME
fi
else
# Create user
if [ "${USER_GID}" = "automatic" ]; then
groupadd $USERNAME
else
groupadd --gid $USER_GID $USERNAME
fi
if [ "${USER_UID}" = "automatic" ]; then
useradd -s /bin/bash --gid $USERNAME -m $USERNAME
else
useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME
fi
fi
# Add add sudo support for non-root user
if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
chmod 0440 /etc/sudoers.d/$USERNAME
EXISTING_NON_ROOT_USER="${USERNAME}"
fi
# ** Shell customization section **
if [ "${USERNAME}" = "root" ]; then
user_rc_path="/root"
else
user_rc_path="/home/${USERNAME}"
fi
# Restore user .bashrc defaults from skeleton file if it doesn't exist or is empty
if [ ! -f "${user_rc_path}/.bashrc" ] || [ ! -s "${user_rc_path}/.bashrc" ] ; then
cp /etc/skel/.bashrc "${user_rc_path}/.bashrc"
fi
# Restore user .profile defaults from skeleton file if it doesn't exist or is empty
if [ ! -f "${user_rc_path}/.profile" ] || [ ! -s "${user_rc_path}/.profile" ] ; then
cp /etc/skel/.profile "${user_rc_path}/.profile"
fi
# .bashrc/.zshrc snippet
rc_snippet="$(cat << 'EOF'
if [ -z "${USER}" ]; then export USER=$(whoami); fi
if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi
# Display optional first run image specific notice if configured and terminal is interactive
if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then
if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then
cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt"
elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then
cat "/workspaces/.codespaces/shared/first-run-notice.txt"
fi
mkdir -p "$HOME/.config/vscode-dev-containers"
# Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &)
fi
# Set the default git editor if not already set
if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then
if [ "${TERM_PROGRAM}" = "vscode" ]; then
if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then
export GIT_EDITOR="code-insiders --wait"
else
export GIT_EDITOR="code --wait"
fi
fi
fi
EOF
)"
# code shim, it fallbacks to code-insiders if code is not available
cat << 'EOF' > /usr/local/bin/code
#!/bin/sh
get_in_path_except_current() {
which -a "$1" | grep -A1 "$0" | grep -v "$0"
}
code="$(get_in_path_except_current code)"
if [ -n "$code" ]; then
exec "$code" "$@"
elif [ "$(command -v code-insiders)" ]; then
exec code-insiders "$@"
else
echo "code or code-insiders is not installed" >&2
exit 127
fi
EOF
chmod +x /usr/local/bin/code
# systemctl shim - tells people to use 'service' if systemd is not running
cat << 'EOF' > /usr/local/bin/systemctl
#!/bin/sh
set -e
if [ -d "/run/systemd/system" ]; then
exec /bin/systemctl/systemctl "$@"
else
echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services intead. e.g.: \n\nservice --status-all'
fi
EOF
chmod +x /usr/local/bin/systemctl
# Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
codespaces_bash="$(cat \
<<'EOF'
# Codespaces bash prompt theme
__bash_prompt() {
local userpart='`export XIT=$? \
&& [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \
&& [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
local gitbranch='`\
export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \
if [ "${BRANCH}" != "" ]; then \
echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \
&& if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
echo -n " \[\033[1;33m\]✗"; \
fi \
&& echo -n "\[\033[0;36m\]) "; \
fi`'
local lightblue='\[\033[1;34m\]'
local removecolor='\[\033[0m\]'
PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ "
unset -f __bash_prompt
}
__bash_prompt
EOF
)"
codespaces_zsh="$(cat \
<<'EOF'
# Codespaces zsh prompt theme
__zsh_prompt() {
local prompt_username
if [ ! -z "${GITHUB_USER}" ]; then
prompt_username="@${GITHUB_USER}"
else
prompt_username="%n"
fi
PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow
PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd
PROMPT+='$(git_prompt_info)%{$fg[white]%}$ %{$reset_color%}' # Git status
unset -f __zsh_prompt
}
ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "
ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})"
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})"
__zsh_prompt
EOF
)"
# Add notice that Oh My Bash! has been removed from images and how to provide information on how to install manually
omb_readme="$(cat \
<<'EOF'
"Oh My Bash!" has been removed from this image in favor of a simple shell prompt. If you
still wish to use it, remove "~/.oh-my-bash" and install it from: https://github.com/ohmybash/oh-my-bash
You may also want to consider "Bash-it" as an alternative: https://github.com/bash-it/bash-it
See here for infomation on adding it to your image or dotfiles: https://aka.ms/codespaces/omb-remove
EOF
)"
omb_stub="$(cat \
<<'EOF'
#!/usr/bin/env bash
if [ -t 1 ]; then
cat $HOME/.oh-my-bash/README.md
fi
EOF
)"
# Add RC snippet and custom bash prompt
if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
echo "${rc_snippet}" >> /etc/bash.bashrc
echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc"
echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc"
if [ "${USERNAME}" != "root" ]; then
echo "${codespaces_bash}" >> "/root/.bashrc"
echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc"
fi
chown ${USERNAME}:${USERNAME} "${user_rc_path}/.bashrc"
RC_SNIPPET_ALREADY_ADDED="true"
fi
# Add stub for Oh My Bash!
if [ ! -d "${user_rc_path}/.oh-my-bash}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then
mkdir -p "${user_rc_path}/.oh-my-bash" "/root/.oh-my-bash"
echo "${omb_readme}" >> "${user_rc_path}/.oh-my-bash/README.md"
echo "${omb_stub}" >> "${user_rc_path}/.oh-my-bash/oh-my-bash.sh"
chmod +x "${user_rc_path}/.oh-my-bash/oh-my-bash.sh"
if [ "${USERNAME}" != "root" ]; then
echo "${omb_readme}" >> "/root/.oh-my-bash/README.md"
echo "${omb_stub}" >> "/root/.oh-my-bash/oh-my-bash.sh"
chmod +x "/root/.oh-my-bash/oh-my-bash.sh"
fi
chown -R "${USERNAME}:${USERNAME}" "${user_rc_path}/.oh-my-bash"
fi
# Optionally install and configure zsh and Oh My Zsh!
if [ "${INSTALL_ZSH}" = "true" ]; then
if ! type zsh > /dev/null 2>&1; then
apt_get_update_if_needed
apt-get install -y zsh
fi
if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then
echo "${rc_snippet}" >> /etc/zsh/zshrc
ZSH_ALREADY_INSTALLED="true"
fi
# Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme.
# See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script.
oh_my_install_dir="${user_rc_path}/.oh-my-zsh"
if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then
template_path="${oh_my_install_dir}/templates/zshrc.zsh-template"
user_rc_file="${user_rc_path}/.zshrc"
umask g-w,o-w
mkdir -p ${oh_my_install_dir}
git clone --depth=1 \
-c core.eol=lf \
-c core.autocrlf=false \
-c fsck.zeroPaddedFilemode=ignore \
-c fetch.fsck.zeroPaddedFilemode=ignore \
-c receive.fsck.zeroPaddedFilemode=ignore \
"https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1
echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file}
sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file}
mkdir -p ${oh_my_install_dir}/custom/themes
echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme"
# Shrink git while still enabling updates
cd "${oh_my_install_dir}"
git repack -a -d -f --depth=1 --window=1
# Copy to non-root user if one is specified
if [ "${USERNAME}" != "root" ]; then
cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root
chown -R ${USERNAME}:${USERNAME} "${user_rc_path}"
fi
fi
fi
# Persist image metadata info, script if meta.env found in same directory
meta_info_script="$(cat << 'EOF'
#!/bin/sh
. /usr/local/etc/vscode-dev-containers/meta.env
# Minimal output
if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then
echo "${VERSION}"
exit 0
elif [ "$1" = "release" ]; then
echo "${GIT_REPOSITORY_RELEASE}"
exit 0
elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then
echo "${CONTENTS_URL}"
exit 0
fi
#Full output
echo
echo "Development container image information"
echo
if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi
if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi
if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi
if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi
if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi
if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi
if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi
echo
EOF
)"
if [ -f "${SCRIPT_DIR}/meta.env" ]; then
mkdir -p /usr/local/etc/vscode-dev-containers/
cp -f "${SCRIPT_DIR}/meta.env" /usr/local/etc/vscode-dev-containers/meta.env
echo "${meta_info_script}" > /usr/local/bin/devcontainer-info
chmod +x /usr/local/bin/devcontainer-info
fi
# Write marker file
mkdir -p "$(dirname "${MARKER_FILE}")"
echo -e "\
PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\
ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}"
echo "Done!"

@ -0,0 +1,230 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md
# Maintainer: The VS Code and Codespaces Teams
#
# Syntax: ./docker-in-docker-debian.sh [enable non-root docker access flag] [non-root user] [use moby]
ENABLE_NONROOT_DOCKER=${1:-"true"}
USERNAME=${2:-"automatic"}
USE_MOBY=${3:-"true"}
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
set -e
if [ "$(id -u)" -ne 0 ]; then
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Determine the appropriate non-root user
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
USERNAME=""
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
USERNAME=${CURRENT_USER}
break
fi
done
if [ "${USERNAME}" = "" ]; then
USERNAME=root
fi
elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
USERNAME=root
fi
# Get central common setting
get_common_setting() {
if [ "${common_settings_file_loaded}" != "true" ]; then
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
common_settings_file_loaded=true
fi
if [ -f "/tmp/vsdc-settings.env" ]; then
local multi_line=""
if [ "$2" = "true" ]; then multi_line="-z"; fi
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
fi
echo "$1=${!1}"
}
# Function to run apt-get if needed
apt_get_update_if_needed()
{
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}
# Checks if packages are installed and installs them if not
check_packages() {
if ! dpkg -s "$@" > /dev/null 2>&1; then
apt_get_update_if_needed
apt-get -y install --no-install-recommends "$@"
fi
}
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
# Install dependencies
check_packages apt-transport-https curl ca-certificates lxc pigz iptables gnupg2
# Swap to legacy iptables for compatibility
if type iptables-legacy > /dev/null 2>&1; then
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
fi
# Install Docker / Moby CLI if not already installed
if type docker > /dev/null 2>&1 && type dockerd > /dev/null 2>&1; then
echo "Docker / Moby CLI and Engine already installed."
else
# Source /etc/os-release to get OS info
. /etc/os-release
if [ "${USE_MOBY}" = "true" ]; then
# Import key safely (new 'signed-by' method rather than deprecated apt-key approach) and install
get_common_setting MICROSOFT_GPG_KEYS_URI
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
apt-get update
apt-get -y install --no-install-recommends moby-cli moby-buildx moby-compose moby-engine
else
# Import key safely (new 'signed-by' method rather than deprecated apt-key approach) and install
curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get -y install --no-install-recommends docker-ce-cli docker-ce
fi
fi
echo "Finished installing docker / moby"
# Install Docker Compose if not already installed and is on a supported architecture
if type docker-compose > /dev/null 2>&1; then
echo "Docker Compose already installed."
else
TARGET_COMPOSE_ARCH="$(uname -m)"
if [ "${TARGET_COMPOSE_ARCH}" = "amd64" ]; then
TARGET_COMPOSE_ARCH="x86_64"
fi
if [ "${TARGET_COMPOSE_ARCH}" != "x86_64" ]; then
# Use pip to get a version that runns on this architecture
if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv pipx > /dev/null 2>&1; then
apt_get_update_if_needed
apt-get -y install python3-minimal python3-pip libffi-dev python3-venv pipx
fi
export PIPX_HOME=/usr/local/pipx
mkdir -p ${PIPX_HOME}
export PIPX_BIN_DIR=/usr/local/bin
export PIP_CACHE_DIR=/tmp/pip-tmp/cache
pipx install --system-site-packages --pip-args '--no-cache-dir --force-reinstall' docker-compose
rm -rf /tmp/pip-tmp
else
LATEST_COMPOSE_VERSION=$(basename "$(curl -fsSL -o /dev/null -w "%{url_effective}" https://github.com/docker/compose/releases/latest)")
curl -fsSL "https://github.com/docker/compose/releases/download/${LATEST_COMPOSE_VERSION}/docker-compose-$(uname -s)-${TARGET_COMPOSE_ARCH}" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
fi
fi
# If init file already exists, exit
if [ -f "/usr/local/share/docker-init.sh" ]; then
echo "/usr/local/share/docker-init.sh already exists, so exiting."
exit 0
fi
echo "docker-init doesnt exist..."
# Add user to the docker group
if [ "${ENABLE_NONROOT_DOCKER}" = "true" ]; then
if ! getent group docker > /dev/null 2>&1; then
groupadd docker
fi
usermod -aG docker ${USERNAME}
fi
tee /usr/local/share/docker-init.sh > /dev/null \
<< 'EOF'
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
sudoIf()
{
if [ "$(id -u)" -ne 0 ]; then
sudo "$@"
else
"$@"
fi
}
# explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly
# ie: docker kill <ID>
sudoIf find /run /var/run -iname 'docker*.pid' -delete || :
sudoIf find /run /var/run -iname 'container*.pid' -delete || :
set -e
## Dind wrapper script from docker team
# Maintained: https://github.com/moby/moby/blob/master/hack/dind
export container=docker
if [ -d /sys/kernel/security ] && ! sudoIf mountpoint -q /sys/kernel/security; then
sudoIf mount -t securityfs none /sys/kernel/security || {
echo >&2 'Could not mount /sys/kernel/security.'
echo >&2 'AppArmor detection and --privileged mode might break.'
}
fi
# Mount /tmp (conditionally)
if ! sudoIf mountpoint -q /tmp; then
sudoIf mount -t tmpfs none /tmp
fi
# cgroup v2: enable nesting
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
# move the init process (PID 1) from the root group to the /init group,
# otherwise writing subtree_control fails with EBUSY.
sudoIf mkdir -p /sys/fs/cgroup/init
sudoIf echo 1 > /sys/fs/cgroup/init/cgroup.procs
# enable controllers
sudoIf sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \
> /sys/fs/cgroup/cgroup.subtree_control
fi
## Dind wrapper over.
# Handle DNS
set +e
cat /etc/resolv.conf | grep -i 'internal.cloudapp.net'
if [ $? -eq 0 ]
then
echo "Setting dockerd Azure DNS."
CUSTOMDNS="--dns 168.63.129.16"
else
echo "Not setting dockerd DNS manually."
CUSTOMDNS=""
fi
set -e
# Start docker/moby engine
( sudoIf dockerd $CUSTOMDNS > /tmp/dockerd.log 2>&1 ) &
set +e
# Execute whatever commands were passed in (if any). This allows us
# to set this script to ENTRYPOINT while still executing the default CMD.
exec "$@"
EOF
chmod +x /usr/local/share/docker-init.sh
chown ${USERNAME}:root /usr/local/share/docker-init.sh

@ -27,7 +27,7 @@ jobs:
uses: actions/setup-node@v1 uses: actions/setup-node@v1
# https://github.com/marketplace/actions/setup-node-js-environment # https://github.com/marketplace/actions/setup-node-js-environment
with: with:
node-version: 12.x node-version: 14.x
- name: Cache node modules - name: Cache node modules
uses: actions/cache@v2 uses: actions/cache@v2
@ -43,7 +43,7 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- name: NPM Install - name: NPM Install
run: npm install run: npm ci
- name: Check i18n Compliance - name: Check i18n Compliance
run: npm run i18n:check run: npm run i18n:check

@ -11,7 +11,7 @@ on:
- 'fix/**' - 'fix/**'
env: env:
PHP_VERSION: 7.3 PHP_VERSION: 7.4
WP_MULTISITE: 0 WP_MULTISITE: 0
jobs: jobs:
@ -29,7 +29,7 @@ jobs:
# https://github.com/marketplace/actions/setup-php-action # https://github.com/marketplace/actions/setup-php-action
with: with:
php-version: ${{ env.PHP_VERSION }} php-version: ${{ env.PHP_VERSION }}
tools: composer:v1 tools: composer:v2
- name: Cache Composer dependencies - name: Cache Composer dependencies
uses: actions/cache@v2 uses: actions/cache@v2

@ -7,8 +7,8 @@ on:
pull_request: pull_request:
env: env:
PHP_PREF_MIN_VERSION: '7.3' PHP_STABLE_VERSION: '7.4'
WP_STABLE_VERSION: '5.6.*' WP_PREF_STABLE_VERSION: '5.7.*'
WP_MULTISITE: 0 WP_MULTISITE: 0
jobs: jobs:
@ -19,10 +19,10 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- job-name: 'Latest Stable Requirements' - job-name: 'Preferred Stable Requirements'
bleeding-edge: false bleeding-edge: false
php-version: '7.3' php-version: '7.4'
wordpress-version: '5.6.*' wordpress-version: '5.7.*'
wp-multisite-mode: 0 wp-multisite-mode: 0
name: '${{ matrix.job-name }} (PHP:${{ matrix.php-version }}/WP:${{ matrix.wordpress-version }})' name: '${{ matrix.job-name }} (PHP:${{ matrix.php-version }}/WP:${{ matrix.wordpress-version }})'
@ -36,13 +36,13 @@ jobs:
# https://github.com/marketplace/actions/setup-php-action # https://github.com/marketplace/actions/setup-php-action
with: with:
php-version: ${{ matrix.php-version }} php-version: ${{ matrix.php-version }}
tools: composer:v1 tools: composer:v2
- name: Setup Node Environment - name: Setup Node Environment
uses: actions/setup-node@v1 uses: actions/setup-node@v1
# https://github.com/marketplace/actions/setup-node-js-environment # https://github.com/marketplace/actions/setup-node-js-environment
with: with:
node-version: 12.x node-version: 14.x
- name: Cache Composer dependencies - name: Cache Composer dependencies
uses: actions/cache@v2 uses: actions/cache@v2
@ -57,20 +57,13 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- name: Require Specified WordPress Version - name: Require Specified WordPress Version
run: composer require wordpress/wordpress:${{ matrix.wordpress-version }} --dev --prefer-source --update-with-all-dependencies run: composer require johnpbloch/wordpress-core:${{ matrix.wordpress-version }} --dev --prefer-source --update-with-all-dependencies
- name: Update Composer Lockfile for Specified WordPress Version - name: Install Composer Dependencies
run: composer update wordpress/wordpress:${{ matrix.wordpress-version }} --lock --prefer-source run: composer install
- name: PHPUnit PHP 7.4 Support
if: matrix.php-version == '7.4'
run: |
composer global require phpunit/php-code-coverage=dev-master
composer global require sebastian/global-state:dev-master
composer global require phpunit/phpunit=dev-master
- name: NPM Setup - name: NPM Setup
run: npm install run: npm ci
- name: Unit Tests - name: Unit Tests
run: npm run test run: npm run test

@ -23,7 +23,7 @@ jobs:
uses: actions/setup-node@v1 uses: actions/setup-node@v1
# https://github.com/marketplace/actions/setup-node-js-environment # https://github.com/marketplace/actions/setup-node-js-environment
with: with:
node-version: 12.x node-version: 14.x
- name: Cache Node Modules - name: Cache Node Modules
uses: actions/cache@v2 uses: actions/cache@v2
@ -39,7 +39,7 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- name: NPM Install - name: NPM Install
run: npm install run: npm ci
- name: Prepare a WordPress.org Release - name: Prepare a WordPress.org Release
run: npm run release run: npm run release

@ -11,10 +11,10 @@ on:
- 'fix/**' - 'fix/**'
env: env:
PHP_VERSION: 7.3 PHP_VERSION: 7.4
WP_MODE: 'single' WP_MODE: 'single'
WP_MULTISITE: 0 WP_MULTISITE: 0
WP_VERSION: '5.6.*' WP_VERSION: '5.7.*'
jobs: jobs:
check: check:
@ -31,7 +31,7 @@ jobs:
# https://github.com/marketplace/actions/setup-php-action # https://github.com/marketplace/actions/setup-php-action
with: with:
php-version: ${{ env.PHP_VERSION }} php-version: ${{ env.PHP_VERSION }}
tools: composer:v1 tools: composer:v2
- name: Cache Composer dependencies - name: Cache Composer dependencies
uses: actions/cache@v2 uses: actions/cache@v2
@ -46,7 +46,7 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- name: Require Specified WordPress Version - name: Require Specified WordPress Version
run: composer require wordpress/wordpress:${{ env.WP_VERSION }} --dev --prefer-source --update-with-all-dependencies run: composer require johnpbloch/wordpress-core:${{ env.WP_VERSION }} --dev --prefer-source --update-with-all-dependencies
- name: Install Composer Dependencies - name: Install Composer Dependencies
run: composer install run: composer install

@ -13,12 +13,13 @@ on:
- 'fix/**' - 'fix/**'
env: env:
PHP_MIN_VERSION: '7.1' PHP_MIN_VERSION: '7.2'
PHP_PREF_MIN_VERSION: '7.2' PHP_PREF_MIN_VERSION: '7.3'
PHP_STABLE_VERSION: '7.4' PHP_STABLE_VERSION: '7.4'
WP_MIN_VERSION: '5.3.*' WP_MIN_VERSION: '5.5.*'
WP_PREF_MIN_VERSION: '5.4.*' WP_PREF_MIN_VERSION: '5.6.*'
WP_STABLE_VERSION: '5.6.*' WP_PREF_STABLE_VERSION: '5.7.*'
WP_STABLE_VERSION: '5.8.*'
jobs: jobs:
test: test:
@ -31,28 +32,33 @@ jobs:
include: include:
- job-name: 'Latest Stable Requirements' - job-name: 'Latest Stable Requirements'
bleeding-edge: false bleeding-edge: false
php-version: '7.3' php-version: '7.4'
wordpress-version: '5.6.*' wordpress-version: '5.8.*'
wp-multisite-mode: 0
- job-name: 'Preferred Stable Requirements'
bleeding-edge: false
php-version: '7.4'
wordpress-version: '5.7.*'
wp-multisite-mode: 0 wp-multisite-mode: 0
- job-name: 'Preferred Minimum Requirements' - job-name: 'Preferred Minimum Requirements'
bleeding-edge: false bleeding-edge: false
php-version: '7.2' php-version: '7.3'
wordpress-version: '5.4.*' wordpress-version: '5.6.*'
wp-multisite-mode: 0 wp-multisite-mode: 0
- job-name: 'Minimum Requirements' - job-name: 'Minimum Requirements'
bleeding-edge: false bleeding-edge: false
php-version: '7.1' php-version: '7.2'
wordpress-version: '5.3.*' wordpress-version: '5.5.*'
wp-multisite-mode: 0 wp-multisite-mode: 0
- job-name: 'Bleeding Edge Requirements' - job-name: 'Bleeding Edge Requirements'
bleeding-edge: true bleeding-edge: true
php-version: '7.4' php-version: '8.0'
wordpress-version: 'dev-master' wordpress-version: 'dev-master'
wp-multisite-mode: 0 wp-multisite-mode: 0
- job-name: 'Multisite Compatibility Requirements' - job-name: 'Multisite Compatibility Requirements'
bleeding-edge: false bleeding-edge: false
php-version: '7.3' php-version: '7.4'
wordpress-version: '5.6.*' wordpress-version: '5.7.*'
wp-multisite-mode: 1 wp-multisite-mode: 1
name: '${{ matrix.job-name }} (PHP:${{ matrix.php-version }}/WP:${{ matrix.wordpress-version }})' name: '${{ matrix.job-name }} (PHP:${{ matrix.php-version }}/WP:${{ matrix.wordpress-version }})'
@ -66,13 +72,13 @@ jobs:
# https://github.com/marketplace/actions/setup-php-action # https://github.com/marketplace/actions/setup-php-action
with: with:
php-version: ${{ matrix.php-version }} php-version: ${{ matrix.php-version }}
tools: composer:v1 tools: composer:v2
- name: Setup Node Environment - name: Setup Node Environment
uses: actions/setup-node@v1 uses: actions/setup-node@v1
# https://github.com/marketplace/actions/setup-node-js-environment # https://github.com/marketplace/actions/setup-node-js-environment
with: with:
node-version: 12.x node-version: 14.x
- name: Cache Composer dependencies - name: Cache Composer dependencies
uses: actions/cache@v2 uses: actions/cache@v2
@ -87,20 +93,25 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- name: Require Specified WordPress Version - name: Require Specified WordPress Version
run: composer require wordpress/wordpress:${{ matrix.wordpress-version }} --dev --prefer-source --update-with-all-dependencies run: composer require johnpbloch/wordpress-core:${{ matrix.wordpress-version }} --dev --prefer-source --update-with-all-dependencies
- name: Update Composer Lockfile for Specified WordPress Version
run: composer update wordpress/wordpress:${{ matrix.wordpress-version }} --lock --prefer-source
- name: PHPUnit PHP 7.4 Support - name: PHPUnit PHP 8.0 Support
if: matrix.php-version == '7.4' if: matrix.php-version == '8.0'
run: | run: |
composer global require phpunit/php-code-coverage=dev-master composer require sebastian/code-unit:^2.0 --dev -W --ignore-platform-req=php
composer global require sebastian/global-state:dev-master composer require phpunit/phpunit:dev-master --dev -W --ignore-platform-req=php
composer global require phpunit/phpunit=dev-master composer require phpro/grumphp:dev-master --dev -W --ignore-platform-req=php
- name: Install Composer Dependencies (PHP 8.0)
if: matrix.php-version == '8.0'
run: composer install --ignore-platform-req=php
- name: Install Composer Dependencies
if: matrix.php-version != '8.0'
run: composer install
- name: NPM Setup - name: NPM Setup
run: npm install run: npm ci
- name: Unit Tests - name: Unit Tests
env: env:

@ -0,0 +1,17 @@
# List the start up tasks. Learn more https://www.gitpod.io/docs/config-start-tasks/
tasks:
- name: WordPress Development Environment
init: npm run setup # runs during prebuild
command: |
npm start -- --update
npm stop
npm start -- --update
# List the ports to expose. Learn more https://www.gitpod.io/docs/config-ports/
ports:
- port: 8888
onOpen: notify
visibility: public
- port: 8889
onOpen: notify
visibility: public

@ -1 +1 @@
lts/erbium lts/fermium

16
.vscode/tasks.json vendored

@ -0,0 +1,16 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"label": "npm: build",
"detail": "npm run grunt build"
}
]
}

@ -1,6 +1,6 @@
{ {
"core": "./wordpress/build", "core": "./wordpress",
"phpVersion": "7.3", "phpVersion": "7.4",
"plugins": [ "plugins": [
"." "."
], ],
@ -12,8 +12,9 @@
"plugins": [ "plugins": [
".", ".",
"https://downloads.wordpress.org/plugin/debug-bar.zip", "https://downloads.wordpress.org/plugin/debug-bar.zip",
"https://downloads.wordpress.org/plugin/query-monitor.zip",
"https://downloads.wordpress.org/plugin/debug-bar-post-meta.zip", "https://downloads.wordpress.org/plugin/debug-bar-post-meta.zip",
"https://downloads.wordpress.org/plugin/display-environment-type.zip",
"https://downloads.wordpress.org/plugin/query-monitor.zip",
"https://downloads.wordpress.org/plugin/transients-manager.zip" "https://downloads.wordpress.org/plugin/transients-manager.zip"
] ]
}, },

@ -1,168 +1,188 @@
# OpenId Connect Generic Changelog # OpenId Connect Generic Changelog
3.8.5 3.9.0
* Fix: @timnolte - Fixes missing URL request validation before use & ensure proper current page URL is setup for Redirect Back.
* Fix: @timnolte - Fixes Redirect URL Logic to Handle Sub-directory Installs.
* Fix: @timnolte - Fixes to provide proper redirect user back for the openid_connect_generic_auth_url shortcode.
3.8.4 - Feature: @matchaxnb - Added support for additional configuration constants.
* Fix: @timnolte - Fixed invalid State object access for redirection handling. - Feature: @schanzen - Added support for agregated claims.
* Improvement: @timnolte - Fixed local wp-env Docker development environment. - Fix: @rkcreation - Fixed access token not updating user metadata after login.
* Improvement: @timnolte - Fixed Composer scripts for linting and static analysis. - Fix: @danc1248 - Fixed user creation issue on Multisite Networks.
- Feature: @RobjS - Added plugin singleton to support for more developer customization.
- Feature: @jkouris - Added action hook to allow custom handling of session expiration.
- Fix: @tommcc - Fixed admin CSS loading only on the plugin settings screen.
- Feature: @rkcreation - Added method to refresh the user claim.
- Feature: @Glowsome - Added acr_values support & verification checks that it when defined in options is honored.
- Fix: @timnolte - Fixed regression which caused improper fallback on missing claims.
- Fix: @slykar - Fixed missing query string handling in redirect URL.
- Fix: @timnolte - Fixed issue with some user linking and user creation handling.
- Improvement: @timnolte - Fixed plugin settings typos and screen formatting.
- Security: @timnolte - Updated build tooling security vulnerabilities.
- Improvement: @timnolte - Changed build tooling scripts.
3.8.3 3.8.5
* Fix: @timnolte - Fixed problems with proper redirect handling. - Fix: @timnolte - Fixed missing URL request validation before use & ensure proper current page URL is setup for Redirect Back.
* Improvement: @timnolte - Changes redirect handling to use State instead of cookies. - Fix: @timnolte - Fixed Redirect URL Logic to Handle Sub-directory Installs.
* Improvement: @timnolte - Refactored additional code to meet coding standards. - Fix: @timnolte - Fixed issue with redirecting user back when the openid_connect_generic_auth_url shortcode is used.
3.8.2 3.8.4
* Fix: @timnolte - Fixed reported XSS vulnerability on WordPress login screen. - Fix: @timnolte - Fixed invalid State object access for redirection handling.
- Improvement: @timnolte - Fixed local wp-env Docker development environment.
- Improvement: @timnolte - Fixed Composer scripts for linting and static analysis.
3.8.1 3.8.3
* Fix: @timnolte - Prevent SSO redirect on password protected posts. - Fix: @timnolte - Fixed problems with proper redirect handling.
* Fix: @timnolte - CI/CD build issues. - Improvement: @timnolte - Changes redirect handling to use State instead of cookies.
* Fix: @timnolte - Invalid redirect handling on logout for Auto Login setting. - Improvement: @timnolte - Refactored additional code to meet coding standards.
3.8.0 3.8.2
* Feature: @timnolte - Ability to use 6 new constants for setting client configuration instead of storing in the DB. - Fix: @timnolte - Fixed reported XSS vulnerability on WordPress login screen.
* Improvement: @timnolte - NPM version requirements for development.
* Improvement: @timnolte - Travis CI build fixes.
* Improvement: @timnolte - GrumPHP configuration updates for code contributions.
* Improvement: @timnolte - Refactored to meet WordPress coding standards.
* Improvement: @timnolte - Refactored to provide localization.
* Improvement: @timnolte - Refactored to provide a Docker-based local development environment.
3.7.1 3.8.1
* Fix: Release Version Number. - Fix: @timnolte - Prevent SSO redirect on password protected posts.
- Fix: @timnolte - CI/CD build issues.
- Fix: @timnolte - Invalid redirect handling on logout for Auto Login setting.
3.7.0 3.8.0
- Feature: @timnolte - Ability to use 6 new constants for setting client configuration instead of storing in the DB.
- Improvement: @timnolte - NPM version requirements for development.
- Improvement: @timnolte - Travis CI build fixes.
- Improvement: @timnolte - GrumPHP configuration updates for code contributions.
- Improvement: @timnolte - Refactored to meet WordPress coding standards.
- Improvement: @timnolte - Refactored to provide localization.
- Improvement: @timnolte - Refactored to provide a Docker-based local development environment.
3.7.1
- Fix: Release Version Number.
3.7.0
- Feature: @timnolte - Ability to enable/disable token refresh. Useful for IDPs that don't support token refresh.
- Feature: @timnolte - Support custom redirect URL(`redirect_to`) with the authentication URL & login button shortcodes.
* Feature: @timnolte - Ability to enable/disable token refresh. Useful for IDPs that don't support token refresh.
* Feature: @timnolte - Support custom redirect URL(`redirect_to`) with the authentication URL & login button shortcodes.
- Supports additional attribute overrides including login `button_text`, `endpoint_login`, `scope`, `redirect_uri`. - Supports additional attribute overrides including login `button_text`, `endpoint_login`, `scope`, `redirect_uri`.
3.6.0 3.6.0
* Improvement: @RobjS - Improved error messages during login state failure. - Improvement: @RobjS - Improved error messages during login state failure.
* Improvement: @RobjS - New developer filter for login form button URL. - Improvement: @RobjS - New developer filter for login form button URL.
* Fix: @cs1m0n - Only increment username during new user creation if the "Link existing user" setting is enabled. - Fix: @cs1m0n - Only increment username during new user creation if the "Link existing user" setting is enabled.
* Fix: @xRy-42 - Allow periods and spaces in usernames to match what WordPress core allows. - Fix: @xRy-42 - Allow periods and spaces in usernames to match what WordPress core allows.
* Feature: @benochen - New setting named "Create user if does not exist" determines whether new users are created during login attempts. - Feature: @benochen - New setting named "Create user if does not exist" determines whether new users are created during login attempts.
* Improvement: @flat235 - Username transliteration and normalization. - Improvement: @flat235 - Username transliteration and normalization.
3.5.1 3.5.1
* Fix: @daggerhart - New approach to state management using transients. - Fix: @daggerhart - New approach to state management using transients.
3.5.0 3.5.0
* Readme fix: @thijskh - Fix syntax error in example openid-connect-generic-login-button-text - Readme fix: @thijskh - Fix syntax error in example openid-connect-generic-login-button-text
* Feature: @slavicd - Allow override of the plugin by posting credentials to wp-login.php - Feature: @slavicd - Allow override of the plugin by posting credentials to wp-login.php
* Feature: @gassan - New action on use login - Feature: @gassan - New action on use login
* Fix: @daggerhart - Avoid double question marks in auth url query string - Fix: @daggerhart - Avoid double question marks in auth url query string
* Fix: @drzraf - wp-cli bootstrap must not inhibit custom rewrite rules - Fix: @drzraf - wp-cli bootstrap must not inhibit custom rewrite rules
* Syntax change: @mullikine - Change PHP keywords to comply with PSR2 - Syntax change: @mullikine - Change PHP keywords to comply with PSR2
**3.4.1** **3.4.1**
* Minor documentation update and additional error checking. - Minor documentation update and additional error checking.
**3.4.0** **3.4.0**
* Feature: @drzraf - New filter hook: ability to filter claim and derived user data before user creation. - Feature: @drzraf - New filter hook: ability to filter claim and derived user data before user creation.
* Feature: @anttileppa - State time limit can now be changed on the settings page. - Feature: @anttileppa - State time limit can now be changed on the settings page.
* Fix: @drzraf - Fix PHP notice when using traditional login, $token_response may be empty. - Fix: @drzraf - Fix PHP notice when using traditional login, $token_response may be empty.
* Fix: @drzraf - Fixed a notice when cookie does not contain expected redirect_url - Fix: @drzraf - Fixed a notice when cookie does not contain expected redirect_url
**3.3.1** **3.3.1**
* Prefixing classes for more efficient autoloading. - Prefixing classes for more efficient autoloading.
* Avoid altering global wp_remote_post() parameters. - Avoid altering global wp_remote_post() parameters.
* Minor metadata updates for wp.org - Minor metadata updates for wp.org
**3.3.0** **3.3.0**
* Fix: @pjeby - Handle multiple user sessions better by using the `WP_Session_Tokens` object. Predecessor to fixes for multiple other issues: #49, #50, #51 - Fix: @pjeby - Handle multiple user sessions better by using the `WP_Session_Tokens` object. Predecessor to fixes for multiple other issues: #49, #50, #51
**3.2.1** **3.2.1**
* Bug fix: @svenvanhal - Exit after issuing redirect. Fixes #46 - Bug fix: @svenvanhal - Exit after issuing redirect. Fixes #46
**3.2.0** **3.2.0**
* Feature: @robbiepaul - trigger core action `wp_login` when user is logged in through this plugin - Feature: @robbiepaul - trigger core action `wp_login` when user is logged in through this plugin
* Feature: @moriyoshi - Determine the WP_User display name with replacement tokens on the settings page. Tokens can be any property of the user_claim. - Feature: @moriyoshi - Determine the WP_User display name with replacement tokens on the settings page. Tokens can be any property of the user_claim.
* Feature: New setting to set redirect URL when session expires. - Feature: New setting to set redirect URL when session expires.
* Feature: @robbiepaul - New filter for modifying authentication URL - Feature: @robbiepaul - New filter for modifying authentication URL
* Fix: @cedrox - Adding id_token_hint to logout URL according to spec - Fix: @cedrox - Adding id_token_hint to logout URL according to spec
* Bug fix: Provide port to the request header when requesting the user_claim - Bug fix: Provide port to the request header when requesting the user_claim
**3.1.0** **3.1.0**
* Feature: @rwasef1830 - Refresh tokens - Feature: @rwasef1830 - Refresh tokens
* Feature: @rwasef1830 - Integrated logout support with end_session endpoint - Feature: @rwasef1830 - Integrated logout support with end_session endpoint
* Feature: May use an alternate redirect_uri that doesn't rely on admin-ajax - Feature: May use an alternate redirect_uri that doesn't rely on admin-ajax
* Feature: @ahatherly - Support for IDP behind reverse proxy - Feature: @ahatherly - Support for IDP behind reverse proxy
* Bug fix: @robertstaddon - case insensitive check for Bearer token - Bug fix: @robertstaddon - case insensitive check for Bearer token
* Bug fix: @rwasef1830 - "redirect to origin when auto-sso" cookie issue - Bug fix: @rwasef1830 - "redirect to origin when auto-sso" cookie issue
* Bug fix: @rwasef1830 - PHP Warnings headers already sent due to attempts to redirect and set cookies during login form message - Bug fix: @rwasef1830 - PHP Warnings headers already sent due to attempts to redirect and set cookies during login form message
* Bug fix: @rwasef1830 - expire session when access_token expires if no refresh token found - Bug fix: @rwasef1830 - expire session when access_token expires if no refresh token found
* UX fix: @rwasef1830 - Show login button on error redirect when using auto-sso - UX fix: @rwasef1830 - Show login button on error redirect when using auto-sso
**3.0.8** **3.0.8**
* Feature: @wgengarelly - Added `openid-connect-generic-update-user-using-current-claim` action hook allowing other plugins/themes - Feature: @wgengarelly - Added `openid-connect-generic-update-user-using-current-claim` action hook allowing other plugins/themes
to take action using the fresh claims received when an existing user logs in. to take action using the fresh claims received when an existing user logs in.
**3.0.7** **3.0.7**
* Bug fix: @wgengarelly - When requesting userinfo, send the access token using the Authorization header field as recommended in - Bug fix: @wgengarelly - When requesting userinfo, send the access token using the Authorization header field as recommended in
section 5.3.1 of the specs. section 5.3.1 of the specs.
**3.0.6** **3.0.6**
* Bug fix: @robertstaddon - If "Link Existing Users" is enabled, allow users who login with OpenID Connect to also log in with WordPress credentials - Bug fix: @robertstaddon - If "Link Existing Users" is enabled, allow users who login with OpenID Connect to also log in with WordPress credentials
**3.0.5** **3.0.5**
* Feature: @robertstaddon - Added `[openid_connect_generic_login_button]` shortcode to allow the login button to be placed anywhere - Feature: @robertstaddon - Added `[openid_connect_generic_login_button]` shortcode to allow the login button to be placed anywhere
* Feature: @robertstaddon - Added setting to "Redirect Back to Origin Page" after a successful login instead of redirecting to the home page. - Feature: @robertstaddon - Added setting to "Redirect Back to Origin Page" after a successful login instead of redirecting to the home page.
**3.0.4** **3.0.4**
* Feature: @robertstaddon - Added setting to allow linking existing WordPress user accounts with newly-authenticated OpenID Connect login - Feature: @robertstaddon - Added setting to allow linking existing WordPress user accounts with newly-authenticated OpenID Connect login
**3.0.3** **3.0.3**
* Using WordPresss's is_ssl() for setcookie()'s "secure" parameter - Using WordPresss's is_ssl() for setcookie()'s "secure" parameter
* Bug fix: Incrementing username in case of collision. - Bug fix: Incrementing username in case of collision.
* Bug fix: Wrong error sent when missing token body - Bug fix: Wrong error sent when missing token body
**3.0.2** **3.0.2**
* Added http_request_timeout setting - Added http_request_timeout setting
**3.0.1** **3.0.1**
* Finalizing 3.0.x api - Finalizing 3.0.x api
**3.0** **3.0**
* Complete rewrite to separate concerns - Complete rewrite to separate concerns
* Changed settings keys for clarity (requires updating settings if upgrading from another version) - Changed settings keys for clarity (requires updating settings if upgrading from another version)
* Error logging - Error logging
**2.1** **2.1**
* Working my way closer to spec. Possible breaking change. Now checking for preferred_username as priority. - Working my way closer to spec. Possible breaking change. Now checking for preferred_username as priority.
* New username determination to avoid collisions - New username determination to avoid collisions
**2.0** **2.0**
Complete rewrite Complete rewrite

@ -82,6 +82,13 @@ On the settings page for this plugin (Dashboard > Settings > OpenID Connect Gene
- Userinfo Endpoint URL: `OIDC_ENDPOINT_USERINFO_URL` - Userinfo Endpoint URL: `OIDC_ENDPOINT_USERINFO_URL`
- Token Validation Endpoint URL: `OIDC_ENDPOINT_TOKEN_URL` - Token Validation Endpoint URL: `OIDC_ENDPOINT_TOKEN_URL`
- End Session Endpoint URL: `OIDC_ENDPOINT_LOGOUT_URL` - End Session Endpoint URL: `OIDC_ENDPOINT_LOGOUT_URL`
- OpenID scope: `OIDC_CLIENT_SCOPE` (space separated)
- OpenID login type: `OIDC_LOGIN_TYPE` ('button' or 'auto')
- Enforce privacy: `OIDC_ENFORCE_PRIVACY` (boolean)
- Create user if they do not exist: `OIDC_CREATE_IF_DOES_NOT_EXIST` (boolean)
- Link existing user: `OIDC_LINK_EXISTING_USERS` (boolean)
- Redirect user back to origin page: `OIDC_REDIRECT_USER_BACK` (boolean)
- Redirect on logout: `OIDC_REDIRECT_ON_LOGOUT` (boolean)
## Hooks ## Hooks

@ -1,11 +1,11 @@
# OpenID Connect Generic Client # # OpenID Connect Generic Client #
**Contributors:** [daggerhart](https://profiles.wordpress.org/daggerhart), [tnolte](https://profiles.wordpress.org/tnolte) **Contributors:** [daggerhart](https://profiles.wordpress.org/daggerhart/), [tnolte](https://profiles.wordpress.org/tnolte/)
**Donate link:** http://www.daggerhart.com/ **Donate link:** http://www.daggerhart.com/
**Tags:** security, login, oauth2, openidconnect, apps, authentication, autologin, sso **Tags:** security, login, oauth2, openidconnect, apps, authentication, autologin, sso
**Requires at least:** 4.9 **Requires at least:** 4.9
**Tested up to:** 5.7.1 **Tested up to:** 5.9.2
**Stable tag:** 3.8.5 **Stable tag:** 3.9.0
**Requires PHP:** 7.1 **Requires PHP:** 7.2
**License:** GPLv2 or later **License:** GPLv2 or later
**License URI:** http://www.gnu.org/licenses/gpl-2.0.html **License URI:** http://www.gnu.org/licenses/gpl-2.0.html
@ -51,12 +51,30 @@ On the settings page for this plugin (Dashboard > Settings > OpenID Connect Gene
## Changelog ## ## Changelog ##
### 3.8.5 ### 3.9.0 ###
* Feature: @matchaxnb - Added support for additional configuration constants.
* Feature: @schanzen - Added support for agregated claims.
* Fix: @rkcreation - Fixed access token not updating user metadata after login.
* Fix: @danc1248 - Fixed user creation issue on Multisite Networks.
* Feature: @RobjS - Added plugin singleton to support for more developer customization.
* Feature: @jkouris - Added action hook to allow custom handling of session expiration.
* Fix: @tommcc - Fixed admin CSS loading only on the plugin settings screen.
* Feature: @rkcreation - Added method to refresh the user claim.
* Feature: @Glowsome - Added acr_values support & verification checks that it when defined in options is honored.
* Fix: @timnolte - Fixed regression which caused improper fallback on missing claims.
* Fix: @slykar - Fixed missing query string handling in redirect URL.
* Fix: @timnolte - Fixed issue with some user linking and user creation handling.
* Improvement: @timnolte - Fixed plugin settings typos and screen formatting.
* Security: @timnolte - Updated build tooling security vulnerabilities.
* Improvement: @timnolte - Changed build tooling scripts.
### 3.8.5 ###
* Fix: @timnolte - Fixed missing URL request validation before use & ensure proper current page URL is setup for Redirect Back.
* Fix: @timnolte - Fixed Redirect URL Logic to Handle Sub-directory Installs.
* Fix: @timnolte - Fixed issue with redirecting user back when the openid_connect_generic_auth_url shortcode is used.
* Fix: @timnolte - Fixes missing URL request validation before use & ensure proper current page URL is setup for Redirect Back.
* Fix: @timnolte - Fixes Redirect URL Logic to Handle Sub-directory Installs.
* Fix: @timnolte - Fixes to provide proper redirect user back for the openid_connect_generic_auth_url shortcode.
###
### 3.8.4 ### ### 3.8.4 ###
* Fix: @timnolte - Fixed invalid State object access for redirection handling. * Fix: @timnolte - Fixed invalid State object access for redirection handling.

@ -25,45 +25,46 @@
}, },
"config": { "config": {
"platform": { "platform": {
"php": "7.3" "php": "7.4"
}, },
"optimize-autoloader": true "optimize-autoloader": true,
}, "sort-packages": true,
"repositories": [ "allow-plugins": {
{ "dealerdirect/phpcodesniffer-composer-installer": true,
"type": "git", "phpstan/extension-installer": true,
"url": "https://github.com/wordpress/wordpress-develop" "composer/installers": true,
"johnpbloch/wordpress-core-installer": true,
"phpro/grumphp": true
} }
], },
"require": { "require": {
"php": ">=7.1.0", "php": ">=7.1",
"composer/installers": "~1.0" "composer/installers": "~1.0"
}, },
"require-dev": { "require-dev": {
"php": ">=7.1.0", "php": ">=7.1",
"squizlabs/php_codesniffer": "^3.3", "brain/monkey": "^2.4",
"wp-coding-standards/wpcs": "^2.2", "dealerdirect/phpcodesniffer-composer-installer": "~0.7",
"johnpbloch/wordpress-core": "~5.7.0",
"johnpbloch/wordpress-core-installer": "^2.0",
"mockery/mockery": "^1.3",
"php-stubs/wordpress-stubs": "~5.7.0",
"phpcompatibility/php-compatibility": "^9.0", "phpcompatibility/php-compatibility": "^9.0",
"phpcompatibility/phpcompatibility-wp": "^2.1", "phpcompatibility/phpcompatibility-wp": "^2.1",
"phpmd/phpmd": "^2.6", "phpmd/phpmd": "^2.6",
"phpro/grumphp": "^1.5",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.2",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpunit/phpunit": "^7", "phpunit/phpunit": "^7",
"phpstan/phpstan": "*",
"phpstan/extension-installer": "^1.0",
"szepeviktor/phpstan-wordpress": "*",
"roave/security-advisories": "dev-master", "roave/security-advisories": "dev-master",
"mnsami/composer-custom-directory-installer": "~1.0", "squizlabs/php_codesniffer": "^3.6",
"wordpress/wordpress": "~5.6.0", "szepeviktor/phpstan-wordpress": "^1.0",
"php-stubs/wordpress-stubs": "~5.6.0", "wp-coding-standards/wpcs": "^2.2"
"dealerdirect/phpcodesniffer-composer-installer": "~0.6",
"brain/monkey": "^2.4",
"mockery/mockery": "^1.3",
"phpro/grumphp": "~0.20",
"sensiolabs/security-checker": "^5.0",
"phpstan/phpstan-deprecation-rules": "^0.12"
}, },
"autoload-dev": { "autoload-dev": {
"classmap": [ "classmap": [
"wordpress/src/" "wordpress/"
] ]
}, },
"autoload": { "autoload": {
@ -90,16 +91,12 @@
"phpcs": "vendor/bin/phpcs", "phpcs": "vendor/bin/phpcs",
"phpcbf": "vendor/bin/phpcbf", "phpcbf": "vendor/bin/phpcbf",
"phpstan": "vendor/bin/phpstan", "phpstan": "vendor/bin/phpstan",
"lint": "vendor/bin/phpcs --report=full", "lint": "@phpcs --report=full",
"lint-fix": "vendor/bin/phpcbf", "lint-fix": "@phpcbf",
"analyze": "vendor/bin/phpstan analyze" "analyze": "@phpstan analyze"
}, },
"extra": { "extra": {
"installer-paths": { "wordpress-install-dir": "wordpress",
"{$name}": [
"wordpress/wordpress"
]
},
"phpcodesniffer-search-depth": 5 "phpcodesniffer-search-depth": 5
} }
} }

2119
composer.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,21 @@
# This is the Compose file for command-line services.
# Anything that doesn't need to be run as part of the main `docker-compose up'
# command should reside in here and be invoked by a helper script.
version: "3.7"
services:
dev:
build: .devcontainer
working_dir: /app
user: 1000:1000
volumes:
- .:/app:cached
composer:
build: ./tools/docker/composer
entrypoint: composer
working_dir: /app
user: 1000:1000
volumes:
- .:/app:cached
- ~/.composer:/root/.composer:cached
volumes:
{}

@ -0,0 +1,30 @@
<?php
/**
* Global OIDCG functions.
*
* @package OpenID_Connect_Generic
* @author Jonathan Daggerhart <jonathan@daggerhart.com>
* @copyright 2015-2020 daggerhart
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
*/
/**
* Return a single use authentication URL.
*
* @return string
*/
function oidcg_get_authentication_url() {
return \OpenID_Connect_Generic::instance()->client_wrapper->get_authentication_url();
}
/**
* Refresh a user claim and update the user metadata.
*
* @param WP_User $user The user object.
* @param array $token_response The token response.
*
* @return WP_Error|array
*/
function oidcg_refresh_user_claim( $user, $token_response ) {
return \OpenID_Connect_Generic::instance()->client_wrapper->refresh_user_claim( $user, $token_response );
}

@ -148,6 +148,7 @@ class OpenID_Connect_Generic_Client_Wrapper {
* @return string * @return string
*/ */
public function get_redirect_to() { public function get_redirect_to() {
// @var WP $wp WordPress environment setup class.
global $wp; global $wp;
if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' == $GLOBALS['pagenow'] && isset( $_GET['action'] ) && 'logout' === $_GET['action'] ) { if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' == $GLOBALS['pagenow'] && isset( $_GET['action'] ) && 'logout' === $_GET['action'] ) {
@ -170,8 +171,8 @@ class OpenID_Connect_Generic_Client_Wrapper {
// Capture the current URL if set to redirect back to origin page. // Capture the current URL if set to redirect back to origin page.
if ( $this->settings->redirect_user_back ) { if ( $this->settings->redirect_user_back ) {
if ( ! empty( $wp->request ) ) { if ( ! empty( $wp->request ) ) {
if ( ! empty( $wp->did_permalink ) && $wp->did_permalink ) { if ( ! empty( $wp->did_permalink ) && boolval( $wp->did_permalink ) === true ) {
$redirect_url = home_url( trailingslashit( $wp->request ) ); $redirect_url = home_url( add_query_arg( $_GET, trailingslashit( $wp->request ) ) );
} else { } else {
$redirect_url = home_url( add_query_arg( null, null ) ); $redirect_url = home_url( add_query_arg( null, null ) );
} }
@ -210,6 +211,7 @@ class OpenID_Connect_Generic_Client_Wrapper {
'client_id' => $this->settings->client_id, 'client_id' => $this->settings->client_id,
'redirect_uri' => $this->client->get_redirect_uri(), 'redirect_uri' => $this->client->get_redirect_uri(),
'redirect_to' => $this->get_redirect_to(), 'redirect_to' => $this->get_redirect_to(),
'acr_values' => $this->settings->acr_values,
), ),
$atts, $atts,
'openid_connect_generic_auth_url' 'openid_connect_generic_auth_url'
@ -224,14 +226,21 @@ class OpenID_Connect_Generic_Client_Wrapper {
if ( stripos( $this->settings->endpoint_login, '?' ) !== false ) { if ( stripos( $this->settings->endpoint_login, '?' ) !== false ) {
$separator = '&'; $separator = '&';
} }
$url_format = '%1$s%2$sresponse_type=code&scope=%3$s&client_id=%4$s&state=%5$s&redirect_uri=%6$s';
if ( ! empty( $atts['acr_values'] ) ) {
$url_format .= '&acr_values=%7$s';
}
$url = sprintf( $url = sprintf(
'%1$s%2$sresponse_type=code&scope=%3$s&client_id=%4$s&state=%5$s&redirect_uri=%6$s', $url_format,
$atts['endpoint_login'], $atts['endpoint_login'],
$separator, $separator,
rawurlencode( $atts['scope'] ), rawurlencode( $atts['scope'] ),
rawurlencode( $atts['client_id'] ), rawurlencode( $atts['client_id'] ),
$this->client->new_state( $atts['redirect_to'] ), $this->client->new_state( $atts['redirect_to'] ),
rawurlencode( $atts['redirect_uri'] ) rawurlencode( $atts['redirect_uri'] ),
rawurlencode( $atts['acr_values'] )
); );
$this->logger->log( apply_filters( 'openid-connect-generic-auth-url', $url ), 'make_authentication_url' ); $this->logger->log( apply_filters( 'openid-connect-generic-auth-url', $url ), 'make_authentication_url' );
@ -271,13 +280,16 @@ class OpenID_Connect_Generic_Client_Wrapper {
$refresh_expires = $refresh_token_info['refresh_expires']; $refresh_expires = $refresh_token_info['refresh_expires'];
if ( ! $refresh_token || ( $refresh_expires && $current_time > $refresh_expires ) ) { if ( ! $refresh_token || ( $refresh_expires && $current_time > $refresh_expires ) ) {
wp_logout(); if ( isset( $_SERVER['REQUEST_URI'] ) ) {
do_action( 'openid-connect-generic-session-expired', wp_get_current_user(), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
wp_logout();
if ( $this->settings->redirect_on_logout ) { if ( $this->settings->redirect_on_logout ) {
$this->error_redirect( new WP_Error( 'access-token-expired', __( 'Session expired. Please login again.', 'daggerhart-openid-connect-generic' ) ) ); $this->error_redirect( new WP_Error( 'access-token-expired', __( 'Session expired. Please login again.', 'daggerhart-openid-connect-generic' ) ) );
} }
return; return;
}
} }
$token_result = $this->client->request_new_tokens( $refresh_token ); $token_result = $this->client->request_new_tokens( $refresh_token );
@ -294,6 +306,7 @@ class OpenID_Connect_Generic_Client_Wrapper {
$this->error_redirect( $token_response ); $this->error_redirect( $token_response );
} }
update_user_meta( $user_id, 'openid-connect-generic-last-token-response', $token_response );
$this->save_refresh_token( $manager, $token, $token_response ); $this->save_refresh_token( $manager, $token, $token_response );
} }
@ -510,8 +523,10 @@ class OpenID_Connect_Generic_Client_Wrapper {
$subject_identity = $client->get_subject_identity( $id_token_claim ); $subject_identity = $client->get_subject_identity( $id_token_claim );
$user = $this->get_user_by_identity( $subject_identity ); $user = $this->get_user_by_identity( $subject_identity );
// A pre-existing IDP mapped user wasn't found.
if ( ! $user ) { if ( ! $user ) {
if ( $this->settings->create_if_does_not_exist ) { // If linking existing users or creating new ones call the `create_new_user` method which handles both cases.
if ( $this->settings->link_existing_users || $this->settings->create_if_does_not_exist ) {
$user = $this->create_new_user( $subject_identity, $user_claim ); $user = $this->create_new_user( $subject_identity, $user_claim );
if ( is_wp_error( $user ) ) { if ( is_wp_error( $user ) ) {
$this->error_redirect( $user ); $this->error_redirect( $user );
@ -519,9 +534,6 @@ class OpenID_Connect_Generic_Client_Wrapper {
} else { } else {
$this->error_redirect( new WP_Error( 'identity-not-map-existing-user', __( 'User identity is not linked to an existing WordPress user.', 'daggerhart-openid-connect-generic' ), $user_claim ) ); $this->error_redirect( new WP_Error( 'identity-not-map-existing-user', __( 'User identity is not linked to an existing WordPress user.', 'daggerhart-openid-connect-generic' ), $user_claim ) );
} }
} else {
// Allow plugins / themes to take action using current claims on existing user (e.g. update role).
do_action( 'openid-connect-generic-update-user-using-current-claim', $user, $user_claim );
} }
// Validate the found / created user. // Validate the found / created user.
@ -534,6 +546,7 @@ class OpenID_Connect_Generic_Client_Wrapper {
// Login the found / created user. // Login the found / created user.
$this->login_user( $user, $token_response, $id_token_claim, $user_claim, $subject_identity ); $this->login_user( $user, $token_response, $id_token_claim, $user_claim, $subject_identity );
// Allow plugins / themes to take action once a user is logged in.
do_action( 'openid-connect-generic-user-logged-in', $user ); do_action( 'openid-connect-generic-user-logged-in', $user );
// Log our success. // Log our success.
@ -579,6 +592,65 @@ class OpenID_Connect_Generic_Client_Wrapper {
return true; return true;
} }
/**
* Refresh user claim.
*
* @param WP_User $user The user object.
* @param array $token_response The token response.
*
* @return WP_Error|array
*/
public function refresh_user_claim( $user, $token_response ) {
$client = $this->client;
/**
* The id_token is used to identify the authenticated user, e.g. for SSO.
* The access_token must be used to prove access rights to protected
* resources e.g. for the userinfo endpoint
*/
$id_token_claim = $client->get_id_token_claim( $token_response );
// Allow for other plugins to alter data before validation.
$id_token_claim = apply_filters( 'openid-connect-modify-id-token-claim-before-validation', $id_token_claim );
if ( is_wp_error( $id_token_claim ) ) {
return $id_token_claim;
}
// Validate our id_token has required values.
$valid = $client->validate_id_token_claim( $id_token_claim );
if ( is_wp_error( $valid ) ) {
return $valid;
}
// If userinfo endpoint is set, exchange the token_response for a user_claim.
if ( ! empty( $this->settings->endpoint_userinfo ) && isset( $token_response['access_token'] ) ) {
$user_claim = $client->get_user_claim( $token_response );
} else {
$user_claim = $id_token_claim;
}
if ( is_wp_error( $user_claim ) ) {
return $user_claim;
}
// Validate our user_claim has required values.
$valid = $client->validate_user_claim( $user_claim, $id_token_claim );
if ( is_wp_error( $valid ) ) {
$this->error_redirect( $valid );
return $valid;
}
// Store the tokens for future reference.
update_user_meta( $user->ID, 'openid-connect-generic-last-token-response', $token_response );
update_user_meta( $user->ID, 'openid-connect-generic-last-id-token-claim', $id_token_claim );
update_user_meta( $user->ID, 'openid-connect-generic-last-user-claim', $user_claim );
return $user_claim;
}
/** /**
* Record user meta data, and provide an authorization cookie. * Record user meta data, and provide an authorization cookie.
* *
@ -595,6 +667,8 @@ class OpenID_Connect_Generic_Client_Wrapper {
update_user_meta( $user->ID, 'openid-connect-generic-last-token-response', $token_response ); update_user_meta( $user->ID, 'openid-connect-generic-last-token-response', $token_response );
update_user_meta( $user->ID, 'openid-connect-generic-last-id-token-claim', $id_token_claim ); update_user_meta( $user->ID, 'openid-connect-generic-last-id-token-claim', $id_token_claim );
update_user_meta( $user->ID, 'openid-connect-generic-last-user-claim', $user_claim ); update_user_meta( $user->ID, 'openid-connect-generic-last-user-claim', $user_claim );
// Allow plugins / themes to take action using current claims on existing user (e.g. update role).
do_action( 'openid-connect-generic-update-user-using-current-claim', $user, $user_claim );
// Create the WP session, so we know its token. // Create the WP session, so we know its token.
$expiration = time() + apply_filters( 'auth_cookie_expiration', 2 * DAY_IN_SECONDS, $user->ID, false ); $expiration = time() + apply_filters( 'auth_cookie_expiration', 2 * DAY_IN_SECONDS, $user->ID, false );
@ -656,10 +730,12 @@ class OpenID_Connect_Generic_Client_Wrapper {
'value' => $subject_identity, 'value' => $subject_identity,
), ),
), ),
// Override the default blog_id (get_current_blog_id) to find users on different sites of a multisite install.
'blog_id' => 0,
) )
); );
// If we found an existing users, grab the first one returned. // If we found existing users, grab the first one returned.
if ( $user_query->get_total() > 0 ) { if ( $user_query->get_total() > 0 ) {
$users = $user_query->get_results(); $users = $user_query->get_results();
return $users[0]; return $users[0];
@ -673,7 +749,7 @@ class OpenID_Connect_Generic_Client_Wrapper {
* *
* @param array $user_claim The IDP authenticated user claim data. * @param array $user_claim The IDP authenticated user claim data.
* *
* @return string|WP_Error|null * @return string|WP_Error
*/ */
private function get_username_from_claim( $user_claim ) { private function get_username_from_claim( $user_claim ) {
@ -683,44 +759,33 @@ class OpenID_Connect_Generic_Client_Wrapper {
// Allow settings to take first stab at username. // Allow settings to take first stab at username.
if ( ! empty( $this->settings->identity_key ) && isset( $user_claim[ $this->settings->identity_key ] ) ) { if ( ! empty( $this->settings->identity_key ) && isset( $user_claim[ $this->settings->identity_key ] ) ) {
$desired_username = $user_claim[ $this->settings->identity_key ]; $desired_username = $user_claim[ $this->settings->identity_key ];
} else if ( isset( $user_claim['preferred_username'] ) && ! empty( $user_claim['preferred_username'] ) ) { }
if ( empty( $desired_username ) && isset( $user_claim['preferred_username'] ) && ! empty( $user_claim['preferred_username'] ) ) {
$desired_username = $user_claim['preferred_username']; $desired_username = $user_claim['preferred_username'];
} else if ( isset( $user_claim['name'] ) && ! empty( $user_claim['name'] ) ) { }
if ( empty( $desired_username ) && isset( $user_claim['name'] ) && ! empty( $user_claim['name'] ) ) {
$desired_username = $user_claim['name']; $desired_username = $user_claim['name'];
} else if ( isset( $user_claim['email'] ) && ! empty( $user_claim['email'] ) ) { }
if ( empty( $desired_username ) && isset( $user_claim['email'] ) && ! empty( $user_claim['email'] ) ) {
$tmp = explode( '@', $user_claim['email'] ); $tmp = explode( '@', $user_claim['email'] );
$desired_username = $tmp[0]; $desired_username = $tmp[0];
} else { }
if ( empty( $desired_username ) ) {
// Nothing to build a name from. // Nothing to build a name from.
return new WP_Error( 'no-username', __( 'No appropriate username found.', 'daggerhart-openid-connect-generic' ), $user_claim ); return new WP_Error( 'no-username', __( 'No appropriate username found.', 'daggerhart-openid-connect-generic' ), $user_claim );
} }
// Normalize the data a bit. // Don't use the full email address for a username.
// @var string $transliterated_username The username converted to ASCII from UTF-8. $_desired_username = explode( '@', $desired_username );
$transliterated_username = iconv( 'UTF-8', 'ASCII//TRANSLIT', $desired_username ); $desired_username = $_desired_username[0];
if ( empty( $transliterated_username ) ) { // Use WordPress Core to sanitize the IDP username.
// translators: $1$s is a username from the IDP. $sanitized_username = sanitize_user( $desired_username, true );
return new WP_Error( 'username-transliteration-failed', sprintf( __( 'Username %1$s could not be transliterated.', 'daggerhart-openid-connect-generic' ), $desired_username ), $desired_username ); if ( empty( $sanitized_username ) ) {
} // translators: %1$s is the santitized version of the username from the IDP.
$normalized_username = strtolower( preg_replace( '/[^a-zA-Z0-9 _.\-@]/', '', $transliterated_username ) ); return new WP_Error( 'username-sanitization-failed', sprintf( __( 'Username %1$s could not be sanitized.', 'daggerhart-openid-connect-generic' ), $desired_username ), $desired_username );
if ( empty( $normalized_username ) ) {
// translators: %1$s is the ASCII version of the username from the IDP.
return new WP_Error( 'username-normalization-failed', sprintf( __( 'Username %1$s could not be normalized.', 'daggerhart-openid-connect-generic' ), $transliterated_username ), $transliterated_username );
} }
// Copy the username for incrementing. return $sanitized_username;
$username = ! empty( $normalized_username ) ? $normalized_username : null;
if ( ! $this->settings->link_existing_users && ! is_null( $username ) ) {
// @example Original user gets "name", second user gets "name2", etc.
$count = 1;
while ( username_exists( $username ) ) {
$count ++;
$username = $normalized_username . $count;
}
}
return $username;
} }
/** /**
@ -745,6 +810,75 @@ class OpenID_Connect_Generic_Client_Wrapper {
return $desired_nickname; return $desired_nickname;
} }
/**
* Checks if $claimname is in the body or _claim_names of the userinfo.
* If yes, returns the claim value. Otherwise, returns false.
*
* @param string $claimname the claim name to look for.
* @param array $userinfo the JSON to look in.
* @param string $claimvalue the source claim value ( from the body of the JWT of the claim source).
* @return true|false
*/
private function get_claim( $claimname, $userinfo, &$claimvalue ) {
/**
* If we find a simple claim, return it.
*/
if ( array_key_exists( $claimname, $userinfo ) ) {
$claimvalue = $userinfo[ $claimname ];
return true;
}
/**
* If there are no aggregated claims, it is over.
*/
if ( ! array_key_exists( '_claim_names', $userinfo ) ||
! array_key_exists( '_claim_sources', $userinfo ) ) {
return false;
}
$claim_src_ptr = $userinfo['_claim_names'];
if ( ! isset( $claim_src_ptr ) ) {
return false;
}
/**
* No reference found
*/
if ( ! array_key_exists( $claimname, $claim_src_ptr ) ) {
return false;
}
$src_name = $claim_src_ptr[ $claimname ];
// Reference found, but no corresponding JWT. This is a malformed userinfo.
if ( ! array_key_exists( $src_name, $userinfo['_claim_sources'] ) ) {
return false;
}
$src = $userinfo['_claim_sources'][ $src_name ];
// Source claim is not a JWT. Abort.
if ( ! array_key_exists( 'JWT', $src ) ) {
return false;
}
/**
* Extract claim from JWT.
* FIXME: We probably want to verify the JWT signature/issuer here.
* For example, using JWKS if applicable. For symmetrically signed
* JWTs (HMAC), we need a way to specify the acceptable secrets
* and each possible issuer in the config.
*/
$jwt = $src['JWT'];
list ( $header, $body, $rest ) = explode( '.', $jwt, 3 );
$body_str = base64_decode( $body, false );
if ( ! $body_str ) {
return false;
}
$body_json = json_decode( $body_str, true );
if ( ! isset( $body_json ) ) {
return false;
}
if ( ! array_key_exists( $claimname, $body_json ) ) {
return false;
}
$claimvalue = $body_json[ $claimname ];
return true;
}
/** /**
* Build a string from the user claim according to the specified format. * Build a string from the user claim according to the specified format.
* *
@ -757,12 +891,13 @@ class OpenID_Connect_Generic_Client_Wrapper {
private function format_string_with_claim( $format, $user_claim, $error_on_missing_key = false ) { private function format_string_with_claim( $format, $user_claim, $error_on_missing_key = false ) {
$matches = null; $matches = null;
$string = ''; $string = '';
$info = '';
$i = 0; $i = 0;
if ( preg_match_all( '/\{[^}]*\}/u', $format, $matches, PREG_OFFSET_CAPTURE ) ) { if ( preg_match_all( '/\{[^}]*\}/u', $format, $matches, PREG_OFFSET_CAPTURE ) ) {
foreach ( $matches[0] as $match ) { foreach ( $matches[0] as $match ) {
$key = substr( $match[0], 1, -1 ); $key = substr( $match[0], 1, -1 );
$string .= substr( $format, $i, $match[1] - $i ); $string .= substr( $format, $i, $match[1] - $i );
if ( ! isset( $user_claim[ $key ] ) ) { if ( ! $this->get_claim( $key, $user_claim, $info ) ) {
if ( $error_on_missing_key ) { if ( $error_on_missing_key ) {
return new WP_Error( return new WP_Error(
'incomplete-user-claim', 'incomplete-user-claim',
@ -776,7 +911,7 @@ class OpenID_Connect_Generic_Client_Wrapper {
); );
} }
} else { } else {
$string .= $user_claim[ $key ]; $string .= $info;
} }
$i = $match[1] + strlen( $match[0] ); $i = $match[1] + strlen( $match[0] );
} }
@ -835,30 +970,30 @@ class OpenID_Connect_Generic_Client_Wrapper {
// Allow claim details to determine username, email, nickname and displayname. // Allow claim details to determine username, email, nickname and displayname.
$_email = $this->get_email_from_claim( $user_claim, true ); $_email = $this->get_email_from_claim( $user_claim, true );
if ( is_wp_error( $_email ) ) { if ( is_wp_error( $_email ) || empty( $_email ) ) {
$values_missing = true; $values_missing = true;
} else if ( ! is_null( $_email ) ) { } else {
$email = $_email; $email = $_email;
} }
$_username = $this->get_username_from_claim( $user_claim ); $_username = $this->get_username_from_claim( $user_claim );
if ( is_wp_error( $_username ) ) { if ( is_wp_error( $_username ) || empty( $_username ) ) {
$values_missing = true; $values_missing = true;
} else if ( ! is_null( $_username ) ) { } else {
$username = $_username; $username = $_username;
} }
$_nickname = $this->get_nickname_from_claim( $user_claim ); $_nickname = $this->get_nickname_from_claim( $user_claim );
if ( is_null( $_nickname ) ) { if ( is_wp_error( $_nickname ) || empty( $_nickname ) ) {
$values_missing = true; $values_missing = true;
} else { } else {
$nickname = $_nickname; $nickname = $_nickname;
} }
$_displayname = $this->get_displayname_from_claim( $user_claim, true ); $_displayname = $this->get_displayname_from_claim( $user_claim, true );
if ( is_wp_error( $_displayname ) ) { if ( is_wp_error( $_displayname ) || empty( $_displayname ) ) {
$values_missing = true; $values_missing = true;
} else if ( ! is_null( $_displayname ) ) { } else {
$displayname = $_displayname; $displayname = $_displayname;
} }
@ -877,39 +1012,48 @@ class OpenID_Connect_Generic_Client_Wrapper {
$_email = $this->get_email_from_claim( $user_claim, true ); $_email = $this->get_email_from_claim( $user_claim, true );
if ( is_wp_error( $_email ) ) { if ( is_wp_error( $_email ) ) {
return $_email; return $_email;
} else if ( ! is_null( $_email ) ) { }
// Use the email address from the latest userinfo request if not empty.
if ( ! empty( $_email ) ) {
$email = $_email; $email = $_email;
} }
$_username = $this->get_username_from_claim( $user_claim ); $_username = $this->get_username_from_claim( $user_claim );
if ( is_wp_error( $_username ) ) { if ( is_wp_error( $_username ) ) {
return $_username; return $_username;
} else if ( ! is_null( $_username ) ) { }
// Use the username from the latest userinfo request if not empty.
if ( ! empty( $_username ) ) {
$username = $_username; $username = $_username;
} }
$_nickname = $this->get_nickname_from_claim( $user_claim ); $_nickname = $this->get_nickname_from_claim( $user_claim );
if ( is_wp_error( $_nickname ) ) { if ( is_wp_error( $_nickname ) ) {
return $_nickname; return $_nickname;
} else if ( is_null( $_nickname ) ) { }
// Use the username as the nickname if the userinfo request nickname is empty.
if ( empty( $_nickname ) ) {
$nickname = $username; $nickname = $username;
} }
$_displayname = $this->get_displayname_from_claim( $user_claim, true ); $_displayname = $this->get_displayname_from_claim( $user_claim, true );
if ( is_wp_error( $_displayname ) ) { if ( is_wp_error( $_displayname ) ) {
return $_displayname; return $_displayname;
} else if ( is_null( $_displayname ) ) { }
// Use the nickname as the displayname if the userinfo request displayname is empty.
if ( empty( $_displayname ) ) {
$displayname = $nickname; $displayname = $nickname;
} }
// Before trying to create the user, first check if a user with the same email already exists. // Before trying to create the user, first check if a matching user exists.
if ( $this->settings->link_existing_users ) { if ( $this->settings->link_existing_users ) {
$uid = null;
if ( $this->settings->identify_with_username ) { if ( $this->settings->identify_with_username ) {
$uid = username_exists( $username ); $uid = username_exists( $username );
} else { } else {
$uid = email_exists( $email ); $uid = email_exists( $email );
} }
if ( $uid ) { if ( ! empty( $uid ) ) {
$user = $this->update_existing_user( $uid, $subject_identity ); $user = $this->update_existing_user( $uid, $subject_identity );
do_action( 'openid-connect-generic-update-user-using-current-claim', $user, $user_claim ); do_action( 'openid-connect-generic-update-user-using-current-claim', $user, $user_claim );
return $user; return $user;
@ -920,12 +1064,22 @@ class OpenID_Connect_Generic_Client_Wrapper {
* Allow other plugins / themes to determine authorization of new accounts * Allow other plugins / themes to determine authorization of new accounts
* based on the returned user claim. * based on the returned user claim.
*/ */
$create_user = apply_filters( 'openid-connect-generic-user-creation-test', true, $user_claim ); $create_user = apply_filters( 'openid-connect-generic-user-creation-test', $this->settings->create_if_does_not_exist, $user_claim );
if ( ! $create_user ) { if ( ! $create_user ) {
return new WP_Error( 'cannot-authorize', __( 'Can not authorize.', 'daggerhart-openid-connect-generic' ), $create_user ); return new WP_Error( 'cannot-authorize', __( 'Can not authorize.', 'daggerhart-openid-connect-generic' ), $create_user );
} }
// Copy the username for incrementing.
$_username = $username;
// Ensure prevention of linking usernames & collisions by incrementing the username if it exists.
// @example Original user gets "name", second user gets "name2", etc.
$count = 1;
while ( username_exists( $username ) ) {
$count ++;
$username = $_username . $count;
}
$user_data = array( $user_data = array(
'user_login' => $username, 'user_login' => $username,
'user_pass' => wp_generate_password( 32, true, true ), 'user_pass' => wp_generate_password( 32, true, true ),

@ -82,6 +82,15 @@ class OpenID_Connect_Generic_Client {
*/ */
private $redirect_uri; private $redirect_uri;
/**
* The specifically requested authentication contract at the IDP
*
* @see OpenID_Connect_Generic_Option_Settings::acr_values
*
* @var string
*/
private $acr_values;
/** /**
* The state time limit. States are only valid for 3 minutes. * The state time limit. States are only valid for 3 minutes.
* *
@ -108,10 +117,11 @@ class OpenID_Connect_Generic_Client {
* @param string $endpoint_userinfo @see OpenID_Connect_Generic_Option_Settings::endpoint_userinfo for description. * @param string $endpoint_userinfo @see OpenID_Connect_Generic_Option_Settings::endpoint_userinfo for description.
* @param string $endpoint_token @see OpenID_Connect_Generic_Option_Settings::endpoint_token for description. * @param string $endpoint_token @see OpenID_Connect_Generic_Option_Settings::endpoint_token for description.
* @param string $redirect_uri @see OpenID_Connect_Generic_Option_Settings::redirect_uri for description. * @param string $redirect_uri @see OpenID_Connect_Generic_Option_Settings::redirect_uri for description.
* @param string $acr_values @see OpenID_Connect_Generic_Option_Settings::acr_values for description.
* @param int $state_time_limit @see OpenID_Connect_Generic_Option_Settings::state_time_limit for description. * @param int $state_time_limit @see OpenID_Connect_Generic_Option_Settings::state_time_limit for description.
* @param OpenID_Connect_Generic_Option_Logger $logger The plugin logging object instance. * @param OpenID_Connect_Generic_Option_Logger $logger The plugin logging object instance.
*/ */
public function __construct( $client_id, $client_secret, $scope, $endpoint_login, $endpoint_userinfo, $endpoint_token, $redirect_uri, $state_time_limit, $logger ) { public function __construct( $client_id, $client_secret, $scope, $endpoint_login, $endpoint_userinfo, $endpoint_token, $redirect_uri, $acr_values, $state_time_limit, $logger ) {
$this->client_id = $client_id; $this->client_id = $client_id;
$this->client_secret = $client_secret; $this->client_secret = $client_secret;
$this->scope = $scope; $this->scope = $scope;
@ -119,6 +129,7 @@ class OpenID_Connect_Generic_Client {
$this->endpoint_userinfo = $endpoint_userinfo; $this->endpoint_userinfo = $endpoint_userinfo;
$this->endpoint_token = $endpoint_token; $this->endpoint_token = $endpoint_token;
$this->redirect_uri = $redirect_uri; $this->redirect_uri = $redirect_uri;
$this->acr_values = $acr_values;
$this->state_time_limit = $state_time_limit; $this->state_time_limit = $state_time_limit;
$this->logger = $logger; $this->logger = $logger;
} }
@ -212,6 +223,10 @@ class OpenID_Connect_Generic_Client {
'headers' => array( 'Host' => $host ), 'headers' => array( 'Host' => $host ),
); );
if ( ! empty( $this->acr_values ) ) {
$request['body'] += array( 'acr_values' => $this->acr_values );
}
// Allow modifications to the request. // Allow modifications to the request.
$request = apply_filters( 'openid-connect-generic-alter-request', $request, 'get-authentication-token' ); $request = apply_filters( 'openid-connect-generic-alter-request', $request, 'get-authentication-token' );
@ -464,6 +479,13 @@ class OpenID_Connect_Generic_Client {
return new WP_Error( 'no-subject-identity', __( 'No subject identity.', 'daggerhart-openid-connect-generic' ), $id_token_claim ); return new WP_Error( 'no-subject-identity', __( 'No subject identity.', 'daggerhart-openid-connect-generic' ), $id_token_claim );
} }
// Validate acr values when the option is set in the configuration.
if ( ! empty( $this->acr_values ) && isset( $id_token_claim['acr'] ) ) {
if ( $this->acr_values != $id_token_claim['acr'] ) {
return new WP_Error( 'no-match-acr', __( 'No matching acr values.', 'daggerhart-openid-connect-generic' ), $id_token_claim );
}
}
return true; return true;
} }

@ -33,6 +33,7 @@
* @property string $endpoint_userinfo The IDP User information endpoint URL. * @property string $endpoint_userinfo The IDP User information endpoint URL.
* @property string $endpoint_token The IDP token validation endpoint URL. * @property string $endpoint_token The IDP token validation endpoint URL.
* @property string $endpoint_end_session The IDP logout endpoint URL. * @property string $endpoint_end_session The IDP logout endpoint URL.
* @property string $acr_values The Authentication contract as defined on the IDP.
* *
* Non-standard Settings: * Non-standard Settings:
* *
@ -86,12 +87,20 @@ class OpenID_Connect_Generic_Option_Settings {
* @var array<string,string> * @var array<string,string>
*/ */
private $environment_settings = array( private $environment_settings = array(
'client_id' => 'OIDC_CLIENT_ID', 'client_id' => 'OIDC_CLIENT_ID',
'client_secret' => 'OIDC_CLIENT_SECRET', 'client_secret' => 'OIDC_CLIENT_SECRET',
'endpoint_login' => 'OIDC_ENDPOINT_LOGIN_URL', 'endpoint_end_session' => 'OIDC_ENDPOINT_LOGOUT_URL',
'endpoint_userinfo' => 'OIDC_ENDPOINT_USERINFO_URL', 'endpoint_login' => 'OIDC_ENDPOINT_LOGIN_URL',
'endpoint_token' => 'OIDC_ENDPOINT_TOKEN_URL', 'endpoint_token' => 'OIDC_ENDPOINT_TOKEN_URL',
'endpoint_end_session' => 'OIDC_ENDPOINT_LOGOUT_URL', 'endpoint_userinfo' => 'OIDC_ENDPOINT_USERINFO_URL',
'login_type' => 'OIDC_LOGIN_TYPE',
'scope' => 'OIDC_CLIENT_SCOPE',
'create_if_does_not_exist' => 'OIDC_CREATE_IF_DOES_NOT_EXIST',
'enforce_privacy' => 'OIDC_ENFORCE_PRIVACY',
'link_existing_users' => 'OIDC_LINK_EXISTING_USERS',
'redirect_on_logout' => 'OIDC_REDIRECT_ON_LOGOUT',
'redirect_user_back' => 'OIDC_REDIRECT_USER_BACK',
'acr_values' => 'OIDC_ACR_VALUES',
); );
/** /**

@ -216,6 +216,7 @@ class OpenID_Connect_Generic_Settings_Page {
'button' => __( 'OpenID Connect button on login form', 'daggerhart-openid-connect-generic' ), 'button' => __( 'OpenID Connect button on login form', 'daggerhart-openid-connect-generic' ),
'auto' => __( 'Auto Login - SSO', 'daggerhart-openid-connect-generic' ), 'auto' => __( 'Auto Login - SSO', 'daggerhart-openid-connect-generic' ),
), ),
'disabled' => defined( 'OIDC_LOGIN_TYPE' ),
'section' => 'client_settings', 'section' => 'client_settings',
), ),
'client_id' => array( 'client_id' => array(
@ -238,6 +239,7 @@ class OpenID_Connect_Generic_Settings_Page {
'description' => __( 'Space separated list of scopes this client should access.', 'daggerhart-openid-connect-generic' ), 'description' => __( 'Space separated list of scopes this client should access.', 'daggerhart-openid-connect-generic' ),
'example' => 'email profile openid offline_access', 'example' => 'email profile openid offline_access',
'type' => 'text', 'type' => 'text',
'disabled' => defined( 'OIDC_CLIENT_SCOPE' ),
'section' => 'client_settings', 'section' => 'client_settings',
), ),
'endpoint_login' => array( 'endpoint_login' => array(
@ -272,6 +274,13 @@ class OpenID_Connect_Generic_Settings_Page {
'disabled' => defined( 'OIDC_ENDPOINT_LOGOUT_URL' ), 'disabled' => defined( 'OIDC_ENDPOINT_LOGOUT_URL' ),
'section' => 'client_settings', 'section' => 'client_settings',
), ),
'acr_values' => array(
'title' => __( 'ACR values', 'daggerhart-openid-connect-generic' ),
'description' => __( 'Use a specific defined authentication contract from the IDP - optional.', 'daggerhart-openid-connect-generic' ),
'type' => 'text',
'disabled' => defined( 'OIDC_ACR_VALUES' ),
'section' => 'client_settings',
),
'identity_key' => array( 'identity_key' => array(
'title' => __( 'Identity Key', 'daggerhart-openid-connect-generic' ), 'title' => __( 'Identity Key', 'daggerhart-openid-connect-generic' ),
'description' => __( 'Where in the user claim array to find the user\'s identification data. Possible standard values: preferred_username, name, or sub. If you\'re having trouble, use "sub".', 'daggerhart-openid-connect-generic' ), 'description' => __( 'Where in the user claim array to find the user\'s identification data. Possible standard values: preferred_username, name, or sub. If you\'re having trouble, use "sub".', 'daggerhart-openid-connect-generic' ),
@ -297,6 +306,7 @@ class OpenID_Connect_Generic_Settings_Page {
'title' => __( 'Enforce Privacy', 'daggerhart-openid-connect-generic' ), 'title' => __( 'Enforce Privacy', 'daggerhart-openid-connect-generic' ),
'description' => __( 'Require users be logged in to see the site.', 'daggerhart-openid-connect-generic' ), 'description' => __( 'Require users be logged in to see the site.', 'daggerhart-openid-connect-generic' ),
'type' => 'checkbox', 'type' => 'checkbox',
'disabled' => defined( 'OIDC_ENFORCE_PRIVACY' ),
'section' => 'authorization_settings', 'section' => 'authorization_settings',
), ),
'alternate_redirect_uri' => array( 'alternate_redirect_uri' => array(
@ -348,24 +358,28 @@ class OpenID_Connect_Generic_Settings_Page {
'title' => __( 'Link Existing Users', 'daggerhart-openid-connect-generic' ), 'title' => __( 'Link Existing Users', 'daggerhart-openid-connect-generic' ),
'description' => __( 'If a WordPress account already exists with the same identity as a newly-authenticated user over OpenID Connect, login as that user instead of generating an error.', 'daggerhart-openid-connect-generic' ), 'description' => __( 'If a WordPress account already exists with the same identity as a newly-authenticated user over OpenID Connect, login as that user instead of generating an error.', 'daggerhart-openid-connect-generic' ),
'type' => 'checkbox', 'type' => 'checkbox',
'disabled' => defined( 'OIDC_LINK_EXISTING_USERS' ),
'section' => 'user_settings', 'section' => 'user_settings',
), ),
'create_if_does_not_exist' => array( 'create_if_does_not_exist' => array(
'title' => __( 'Create user if does not exist', 'daggerhart-openid-connect-generic' ), 'title' => __( 'Create user if does not exist', 'daggerhart-openid-connect-generic' ),
'description' => __( 'If the user identity is not link to an existing Wordpress user, it is created. If this setting is not enabled and if the user authenticates with an account which is not link to an existing Wordpress user then the authentication failed', 'daggerhart-openid-connect-generic' ), 'description' => __( 'If the user identity is not linked to an existing WordPress user, it is created. If this setting is not enabled, and if the user authenticates with an account which is not linked to an existing WordPress user, then the authentication will fail.', 'daggerhart-openid-connect-generic' ),
'type' => 'checkbox', 'type' => 'checkbox',
'disabled' => defined( 'OIDC_CREATE_IF_DOES_NOT_EXIST' ),
'section' => 'user_settings', 'section' => 'user_settings',
), ),
'redirect_user_back' => array( 'redirect_user_back' => array(
'title' => __( 'Redirect Back to Origin Page', 'daggerhart-openid-connect-generic' ), 'title' => __( 'Redirect Back to Origin Page', 'daggerhart-openid-connect-generic' ),
'description' => __( 'After a successful OpenID Connect authentication, this will redirect the user back to the page on which they clicked the OpenID Connect login button. This will cause the login process to proceed in a traditional WordPress fashion. For example, users logging in through the default wp-login.php page would end up on the WordPress Dashboard and users logging in through the WooCommerce "My Account" page would end up on their account page.', 'daggerhart-openid-connect-generic' ), 'description' => __( 'After a successful OpenID Connect authentication, this will redirect the user back to the page on which they clicked the OpenID Connect login button. This will cause the login process to proceed in a traditional WordPress fashion. For example, users logging in through the default wp-login.php page would end up on the WordPress Dashboard and users logging in through the WooCommerce "My Account" page would end up on their account page.', 'daggerhart-openid-connect-generic' ),
'type' => 'checkbox', 'type' => 'checkbox',
'disabled' => defined( 'OIDC_REDIRECT_USER_BACK' ),
'section' => 'user_settings', 'section' => 'user_settings',
), ),
'redirect_on_logout' => array( 'redirect_on_logout' => array(
'title' => __( 'Redirect to the login screen when session is expired', 'daggerhart-openid-connect-generic' ), 'title' => __( 'Redirect to the login screen when session is expired', 'daggerhart-openid-connect-generic' ),
'description' => __( 'When enabled, this will automatically redirect the user back to the WordPress login page if their access token has expired.', 'daggerhart-openid-connect-generic' ), 'description' => __( 'When enabled, this will automatically redirect the user back to the WordPress login page if their access token has expired.', 'daggerhart-openid-connect-generic' ),
'type' => 'checkbox', 'type' => 'checkbox',
'disabled' => defined( 'OIDC_REDIRECT_ON_LOGOUT' ),
'section' => 'user_settings', 'section' => 'user_settings',
), ),
'enable_logging' => array( 'enable_logging' => array(
@ -414,6 +428,8 @@ class OpenID_Connect_Generic_Settings_Page {
* @return void * @return void
*/ */
public function settings_page() { public function settings_page() {
wp_enqueue_style( 'daggerhart-openid-connect-generic-admin', plugin_dir_url( __DIR__ ) . 'css/styles-admin.css', array(), OpenID_Connect_Generic::VERSION, 'all' );
$redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' ); $redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' );
if ( $this->settings->alternate_redirect_uri ) { if ( $this->settings->alternate_redirect_uri ) {
@ -472,9 +488,9 @@ class OpenID_Connect_Generic_Settings_Page {
public function do_text_field( $field ) { public function do_text_field( $field ) {
?> ?>
<input type="<?php print esc_attr( $field['type'] ); ?>" <input type="<?php print esc_attr( $field['type'] ); ?>"
<?php echo ( ! empty( $field['disabled'] ) && boolval( $field['disabled'] ) ) ? ' disabled' : ''; ?> <?php echo ( ! empty( $field['disabled'] ) && boolval( $field['disabled'] ) === true ) ? ' disabled' : ''; ?>
id="<?php print esc_attr( $field['key'] ); ?>" id="<?php print esc_attr( $field['key'] ); ?>"
class="large-text<?php echo ( ! empty( $field['disabled'] ) && boolval( $field['disabled'] ) ) ? ' disabled' : ''; ?>" class="large-text<?php echo ( ! empty( $field['disabled'] ) && boolval( $field['disabled'] ) === true ) ? ' disabled' : ''; ?>"
name="<?php print esc_attr( $field['name'] ); ?>" name="<?php print esc_attr( $field['name'] ); ?>"
value="<?php print esc_attr( $this->settings->{ $field['key'] } ); ?>"> value="<?php print esc_attr( $this->settings->{ $field['key'] } ); ?>">
<?php <?php
@ -530,7 +546,7 @@ class OpenID_Connect_Generic_Settings_Page {
public function do_field_description( $field ) { public function do_field_description( $field ) {
?> ?>
<p class="description"> <p class="description">
<?php print esc_html( $field['description'] ); ?> <?php print wp_kses_post( $field['description'] ); ?>
<?php if ( isset( $field['example'] ) ) : ?> <?php if ( isset( $field['example'] ) ) : ?>
<br/><strong><?php esc_html_e( 'Example', 'daggerhart-openid-connect-generic' ); ?>: </strong> <br/><strong><?php esc_html_e( 'Example', 'daggerhart-openid-connect-generic' ); ?>: </strong>
<code><?php print esc_html( $field['example'] ); ?></code> <code><?php print esc_html( $field['example'] ); ?></code>

@ -1,15 +1,15 @@
# Copyright (C) 2021 daggerhart # Copyright (C) 2022 daggerhart
# This file is distributed under the GPL-2.0+. # This file is distributed under the GPL-2.0+.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: OpenID Connect Generic 3.8.5\n" "Project-Id-Version: OpenID Connect Generic 3.9.0\n"
"Report-Msgid-Bugs-To: " "Report-Msgid-Bugs-To: "
"https://github.com/daggerhart/openid-connect-generic/issues\n" "https://github.com/daggerhart/openid-connect-generic/issues\n"
"POT-Creation-Date: 2021-04-16 03:38:39+00:00\n" "POT-Creation-Date: 2022-03-22 03:28:37+00:00\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2021-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2022-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: en\n" "Language: en\n"
@ -25,122 +25,121 @@ msgstr ""
"X-Textdomain-Support: yes\n" "X-Textdomain-Support: yes\n"
"X-Generator: grunt-wp-i18n 1.0.3\n" "X-Generator: grunt-wp-i18n 1.0.3\n"
#: includes/openid-connect-generic-client-wrapper.php:277 #: includes/openid-connect-generic-client-wrapper.php:288
msgid "Session expired. Please login again." msgid "Session expired. Please login again."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:520 #: includes/openid-connect-generic-client-wrapper.php:535
msgid "User identity is not linked to an existing WordPress user." msgid "User identity is not linked to an existing WordPress user."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:576 #: includes/openid-connect-generic-client-wrapper.php:589
msgid "Invalid user." msgid "Invalid user."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:695 #: includes/openid-connect-generic-client-wrapper.php:775
msgid "No appropriate username found." msgid "No appropriate username found."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:703 #: includes/openid-connect-generic-client-wrapper.php:785
#. translators: $1$s is a username from the IDP. #. translators: %1$s is the santitized version of the username from the IDP.
msgid "Username %1$s could not be transliterated." msgid "Username %1$s could not be sanitized."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:708 #: includes/openid-connect-generic-client-wrapper.php:807
#. translators: %1$s is the ASCII version of the username from the IDP.
msgid "Username %1$s could not be normalized."
msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:742
#. translators: %1$s is the configured User Claim nickname key. #. translators: %1$s is the configured User Claim nickname key.
msgid "No nickname found in user claim using key: %1$s." msgid "No nickname found in user claim using key: %1$s."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:769 #: includes/openid-connect-generic-client-wrapper.php:904
msgid "User claim incomplete." msgid "User claim incomplete."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:871 #: includes/openid-connect-generic-client-wrapper.php:1006
msgid "Bad user claim result." msgid "Bad user claim result."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:926 #: includes/openid-connect-generic-client-wrapper.php:1070
msgid "Can not authorize." msgid "Can not authorize."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client-wrapper.php:945 #: includes/openid-connect-generic-client-wrapper.php:1099
msgid "Failed user creation." msgid "Failed user creation."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:165 #: includes/openid-connect-generic-client.php:176
msgid "Missing state." msgid "Missing state."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:169 #: includes/openid-connect-generic-client.php:180
msgid "Invalid state." msgid "Invalid state."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:184 #: includes/openid-connect-generic-client.php:195
msgid "Missing authentication code." msgid "Missing authentication code."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:223 #: includes/openid-connect-generic-client.php:238
msgid "Request for authentication token failed." msgid "Request for authentication token failed."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:254 #: includes/openid-connect-generic-client.php:269
msgid "Refresh token failed." msgid "Refresh token failed."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:269 #: includes/openid-connect-generic-client.php:284
msgid "Missing token body." msgid "Missing token body."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:277 #: includes/openid-connect-generic-client.php:292
msgid "Invalid token." msgid "Invalid token."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:328 #: includes/openid-connect-generic-client.php:343
msgid "Request for userinfo failed." msgid "Request for userinfo failed."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:388 #: includes/openid-connect-generic-client.php:403
msgid "Missing authentication state." msgid "Missing authentication state."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:425 #: includes/openid-connect-generic-client.php:440
msgid "No identity token." msgid "No identity token."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:432 #: includes/openid-connect-generic-client.php:447
msgid "Missing identity token." msgid "Missing identity token."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:459 #: includes/openid-connect-generic-client.php:474
msgid "Bad ID token claim." msgid "Bad ID token claim."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:464 #: includes/openid-connect-generic-client.php:479
msgid "No subject identity." msgid "No subject identity."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:483 #: includes/openid-connect-generic-client.php:485
msgid "No matching acr values."
msgstr ""
#: includes/openid-connect-generic-client.php:505
msgid "Bad user claim." msgid "Bad user claim."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:503 #: includes/openid-connect-generic-client.php:525
msgid "Invalid user claim." msgid "Invalid user claim."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:508 #: includes/openid-connect-generic-client.php:530
msgid "Error from the IDP." msgid "Error from the IDP."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:517 #: includes/openid-connect-generic-client.php:539
msgid "Incorrect user claim." msgid "Incorrect user claim."
msgstr "" msgstr ""
#: includes/openid-connect-generic-client.php:524 #: includes/openid-connect-generic-client.php:546
msgid "Unauthorized access." msgid "Unauthorized access."
msgstr "" msgstr ""
@ -209,82 +208,90 @@ msgstr ""
msgid "Auto Login - SSO" msgid "Auto Login - SSO"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:222 #: includes/openid-connect-generic-settings-page.php:223
msgid "Client ID" msgid "Client ID"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:223 #: includes/openid-connect-generic-settings-page.php:224
msgid "" msgid ""
"The ID this client will be recognized as when connecting the to Identity " "The ID this client will be recognized as when connecting the to Identity "
"provider server." "provider server."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:230 #: includes/openid-connect-generic-settings-page.php:231
msgid "Client Secret Key" msgid "Client Secret Key"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:231 #: includes/openid-connect-generic-settings-page.php:232
msgid "" msgid ""
"Arbitrary secret key the server expects from this client. Can be anything, " "Arbitrary secret key the server expects from this client. Can be anything, "
"but should be very unique." "but should be very unique."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:237 #: includes/openid-connect-generic-settings-page.php:238
msgid "OpenID Scope" msgid "OpenID Scope"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:238 #: includes/openid-connect-generic-settings-page.php:239
msgid "Space separated list of scopes this client should access." msgid "Space separated list of scopes this client should access."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:244 #: includes/openid-connect-generic-settings-page.php:246
msgid "Login Endpoint URL" msgid "Login Endpoint URL"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:245 #: includes/openid-connect-generic-settings-page.php:247
msgid "Identify provider authorization endpoint." msgid "Identify provider authorization endpoint."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:252 #: includes/openid-connect-generic-settings-page.php:254
msgid "Userinfo Endpoint URL" msgid "Userinfo Endpoint URL"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:253 #: includes/openid-connect-generic-settings-page.php:255
msgid "Identify provider User information endpoint." msgid "Identify provider User information endpoint."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:260 #: includes/openid-connect-generic-settings-page.php:262
msgid "Token Validation Endpoint URL" msgid "Token Validation Endpoint URL"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:261 #: includes/openid-connect-generic-settings-page.php:263
msgid "Identify provider token endpoint." msgid "Identify provider token endpoint."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:268 #: includes/openid-connect-generic-settings-page.php:270
msgid "End Session Endpoint URL" msgid "End Session Endpoint URL"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:269 #: includes/openid-connect-generic-settings-page.php:271
msgid "Identify provider logout endpoint." msgid "Identify provider logout endpoint."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:276 #: includes/openid-connect-generic-settings-page.php:278
msgid "ACR values"
msgstr ""
#: includes/openid-connect-generic-settings-page.php:279
msgid "Use a specific defined authentication contract from the IDP - optional."
msgstr ""
#: includes/openid-connect-generic-settings-page.php:285
msgid "Identity Key" msgid "Identity Key"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:277 #: includes/openid-connect-generic-settings-page.php:286
msgid "" msgid ""
"Where in the user claim array to find the user's identification data. " "Where in the user claim array to find the user's identification data. "
"Possible standard values: preferred_username, name, or sub. If you're " "Possible standard values: preferred_username, name, or sub. If you're "
"having trouble, use \"sub\"." "having trouble, use \"sub\"."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:283 #: includes/openid-connect-generic-settings-page.php:292
msgid "Disable SSL Verify" msgid "Disable SSL Verify"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:285 #: includes/openid-connect-generic-settings-page.php:294
#. translators: %1$s HTML tags for layout/styles, %2$s closing HTML tag for #. translators: %1$s HTML tags for layout/styles, %2$s closing HTML tag for
#. styles. #. styles.
msgid "" msgid ""
@ -295,27 +302,27 @@ msgid ""
"sites.%2$s" "sites.%2$s"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:290 #: includes/openid-connect-generic-settings-page.php:299
msgid "HTTP Request Timeout" msgid "HTTP Request Timeout"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:291 #: includes/openid-connect-generic-settings-page.php:300
msgid "Set the timeout for requests made to the IDP. Default value is 5." msgid "Set the timeout for requests made to the IDP. Default value is 5."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:297 #: includes/openid-connect-generic-settings-page.php:306
msgid "Enforce Privacy" msgid "Enforce Privacy"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:298 #: includes/openid-connect-generic-settings-page.php:307
msgid "Require users be logged in to see the site." msgid "Require users be logged in to see the site."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:303 #: includes/openid-connect-generic-settings-page.php:313
msgid "Alternate Redirect URI" msgid "Alternate Redirect URI"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:304 #: includes/openid-connect-generic-settings-page.php:314
msgid "" msgid ""
"Provide an alternative redirect route. Useful if your server is causing " "Provide an alternative redirect route. Useful if your server is causing "
"issues with the default admin-ajax method. You must flush rewrite rules " "issues with the default admin-ajax method. You must flush rewrite rules "
@ -323,90 +330,90 @@ msgid ""
"settings page." "settings page."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:309 #: includes/openid-connect-generic-settings-page.php:319
msgid "Nickname Key" msgid "Nickname Key"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:310 #: includes/openid-connect-generic-settings-page.php:320
msgid "" msgid ""
"Where in the user claim array to find the user's nickname. Possible " "Where in the user claim array to find the user's nickname. Possible "
"standard values: preferred_username, name, or sub." "standard values: preferred_username, name, or sub."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:316 #: includes/openid-connect-generic-settings-page.php:326
msgid "Email Formatting" msgid "Email Formatting"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:317 #: includes/openid-connect-generic-settings-page.php:327
msgid "" msgid ""
"String from which the user's email address is built. Specify \"{email}\" as " "String from which the user's email address is built. Specify \"{email}\" as "
"long as the user claim contains an email claim." "long as the user claim contains an email claim."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:323 #: includes/openid-connect-generic-settings-page.php:333
msgid "Display Name Formatting" msgid "Display Name Formatting"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:324 #: includes/openid-connect-generic-settings-page.php:334
msgid "String from which the user's display name is built." msgid "String from which the user's display name is built."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:330 #: includes/openid-connect-generic-settings-page.php:340
msgid "Identify with User Name" msgid "Identify with User Name"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:331 #: includes/openid-connect-generic-settings-page.php:341
msgid "" msgid ""
"If checked, the user's identity will be determined by the user name instead " "If checked, the user's identity will be determined by the user name instead "
"of the email address." "of the email address."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:336 #: includes/openid-connect-generic-settings-page.php:346
msgid "State time limit" msgid "State time limit"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:337 #: includes/openid-connect-generic-settings-page.php:347
msgid "State valid time in seconds. Defaults to 180" msgid "State valid time in seconds. Defaults to 180"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:342 #: includes/openid-connect-generic-settings-page.php:352
msgid "Enable Refresh Token" msgid "Enable Refresh Token"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:343 #: includes/openid-connect-generic-settings-page.php:353
msgid "" msgid ""
"If checked, support refresh tokens used to obtain access tokens from " "If checked, support refresh tokens used to obtain access tokens from "
"supported IDPs." "supported IDPs."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:348 #: includes/openid-connect-generic-settings-page.php:358
msgid "Link Existing Users" msgid "Link Existing Users"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:349 #: includes/openid-connect-generic-settings-page.php:359
msgid "" msgid ""
"If a WordPress account already exists with the same identity as a " "If a WordPress account already exists with the same identity as a "
"newly-authenticated user over OpenID Connect, login as that user instead of " "newly-authenticated user over OpenID Connect, login as that user instead of "
"generating an error." "generating an error."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:354 #: includes/openid-connect-generic-settings-page.php:365
msgid "Create user if does not exist" msgid "Create user if does not exist"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:355 #: includes/openid-connect-generic-settings-page.php:366
msgid "" msgid ""
"If the user identity is not link to an existing Wordpress user, it is " "If the user identity is not linked to an existing WordPress user, it is "
"created. If this setting is not enabled and if the user authenticates with " "created. If this setting is not enabled, and if the user authenticates with "
"an account which is not link to an existing Wordpress user then the " "an account which is not linked to an existing WordPress user, then the "
"authentication failed" "authentication will fail."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:360 #: includes/openid-connect-generic-settings-page.php:372
msgid "Redirect Back to Origin Page" msgid "Redirect Back to Origin Page"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:361 #: includes/openid-connect-generic-settings-page.php:373
msgid "" msgid ""
"After a successful OpenID Connect authentication, this will redirect the " "After a successful OpenID Connect authentication, this will redirect the "
"user back to the page on which they clicked the OpenID Connect login " "user back to the page on which they clicked the OpenID Connect login "
@ -417,75 +424,75 @@ msgid ""
"account page." "account page."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:366 #: includes/openid-connect-generic-settings-page.php:379
msgid "Redirect to the login screen when session is expired" msgid "Redirect to the login screen when session is expired"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:367 #: includes/openid-connect-generic-settings-page.php:380
msgid "" msgid ""
"When enabled, this will automatically redirect the user back to the " "When enabled, this will automatically redirect the user back to the "
"WordPress login page if their access token has expired." "WordPress login page if their access token has expired."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:372 #: includes/openid-connect-generic-settings-page.php:386
msgid "Enable Logging" msgid "Enable Logging"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:373 #: includes/openid-connect-generic-settings-page.php:387
msgid "Very simple log messages for debugging purposes." msgid "Very simple log messages for debugging purposes."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:378 #: includes/openid-connect-generic-settings-page.php:392
msgid "Log Limit" msgid "Log Limit"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:379 #: includes/openid-connect-generic-settings-page.php:393
msgid "" msgid ""
"Number of items to keep in the log. These logs are stored as an option in " "Number of items to keep in the log. These logs are stored as an option in "
"the database, so space is limited." "the database, so space is limited."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:439 #: includes/openid-connect-generic-settings-page.php:455
msgid "Notes" msgid "Notes"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:442 #: includes/openid-connect-generic-settings-page.php:458
msgid "Redirect URI" msgid "Redirect URI"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:446 #: includes/openid-connect-generic-settings-page.php:462
msgid "Login Button Shortcode" msgid "Login Button Shortcode"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:450 #: includes/openid-connect-generic-settings-page.php:466
msgid "Authentication URL Shortcode" msgid "Authentication URL Shortcode"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:455 #: includes/openid-connect-generic-settings-page.php:471
msgid "Logs" msgid "Logs"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:535 #: includes/openid-connect-generic-settings-page.php:551
msgid "Example" msgid "Example"
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:548 #: includes/openid-connect-generic-settings-page.php:564
msgid "Enter your OpenID Connect identity provider settings." msgid "Enter your OpenID Connect identity provider settings."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:557 #: includes/openid-connect-generic-settings-page.php:573
msgid "Modify the interaction between OpenID Connect and WordPress users." msgid "Modify the interaction between OpenID Connect and WordPress users."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:566 #: includes/openid-connect-generic-settings-page.php:582
msgid "Control the authorization mechanics of the site." msgid "Control the authorization mechanics of the site."
msgstr "" msgstr ""
#: includes/openid-connect-generic-settings-page.php:575 #: includes/openid-connect-generic-settings-page.php:591
msgid "Log information about login attempts through OpenID Connect Generic." msgid "Log information about login attempts through OpenID Connect Generic."
msgstr "" msgstr ""
#: openid-connect-generic.php:202 #: openid-connect-generic.php:213
msgid "Private site" msgid "Private site"
msgstr "" msgstr ""

@ -16,7 +16,9 @@
* Plugin Name: OpenID Connect Generic * Plugin Name: OpenID Connect Generic
* Plugin URI: https://github.com/daggerhart/openid-connect-generic * Plugin URI: https://github.com/daggerhart/openid-connect-generic
* Description: Connect to an OpenID Connect generic client using Authorization Code Flow. * Description: Connect to an OpenID Connect generic client using Authorization Code Flow.
* Version: 3.8.5 * Version: 3.9.0
* Requires at least: 4.9
* Requires PHP: 7.2
* Author: daggerhart * Author: daggerhart
* Author URI: http://www.daggerhart.com * Author URI: http://www.daggerhart.com
* Text Domain: daggerhart-openid-connect-generic * Text Domain: daggerhart-openid-connect-generic
@ -44,14 +46,16 @@ Notes
- openid-connect-modify-id-token-claim-before-validation - modify the token claim before validation - openid-connect-modify-id-token-claim-before-validation - modify the token claim before validation
Actions Actions
- openid-connect-generic-user-create - 2 args: fires when a new user is created by this plugin - openid-connect-generic-user-create - 2 args: fires when a new user is created by this plugin
- openid-connect-generic-user-update - 1 arg: user ID, fires when user is updated by this plugin - openid-connect-generic-user-update - 1 arg: user ID, fires when user is updated by this plugin
- openid-connect-generic-update-user-using-current-claim - 2 args: fires every time an existing user logs - openid-connect-generic-update-user-using-current-claim - 2 args: fires every time an existing user logs in and the claims are updated.
- openid-connect-generic-redirect-user-back - 2 args: $redirect_url, $user. Allows interruption of redirect during login. - openid-connect-generic-redirect-user-back - 2 args: $redirect_url, $user. Allows interruption of redirect during login.
- openid-connect-generic-user-logged-in - 1 arg: $user, fires when user is logged in. - openid-connect-generic-user-logged-in - 1 arg: $user, fires when user is logged in.
- openid-connect-generic-cron-daily - daily cron action - openid-connect-generic-cron-daily - daily cron action
- openid-connect-generic-state-not-found - the given state does not exist in the database, regardless of its expiration. - openid-connect-generic-state-not-found - the given state does not exist in the database, regardless of its expiration.
- openid-connect-generic-state-expired - the given state exists, but expired before this login attempt. - openid-connect-generic-state-expired - the given state exists, but expired before this login attempt.
Callable actions
User Meta User Meta
- openid-connect-generic-subject-identity - the identity of the user provided by the idp - openid-connect-generic-subject-identity - the identity of the user provided by the idp
@ -75,12 +79,19 @@ Notes
*/ */
class OpenID_Connect_Generic { class OpenID_Connect_Generic {
/**
* Singleton instance of self
*
* @var OpenID_Connect_Generic
*/
protected static $_instance = null;
/** /**
* Plugin version. * Plugin version.
* *
* @var * @var string
*/ */
const VERSION = '3.8.5'; const VERSION = '3.9.0';
/** /**
* Plugin settings. * Plugin settings.
@ -108,7 +119,7 @@ class OpenID_Connect_Generic {
* *
* @var OpenID_Connect_Generic_Client_Wrapper * @var OpenID_Connect_Generic_Client_Wrapper
*/ */
private $client_wrapper; public $client_wrapper;
/** /**
* Setup the plugin * Setup the plugin
@ -121,6 +132,7 @@ class OpenID_Connect_Generic {
public function __construct( OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) { public function __construct( OpenID_Connect_Generic_Option_Settings $settings, OpenID_Connect_Generic_Option_Logger $logger ) {
$this->settings = $settings; $this->settings = $settings;
$this->logger = $logger; $this->logger = $logger;
self::$_instance = $this;
} }
/** /**
@ -130,8 +142,6 @@ class OpenID_Connect_Generic {
*/ */
public function init() { public function init() {
wp_enqueue_style( 'daggerhart-openid-connect-generic-admin', plugin_dir_url( __FILE__ ) . 'css/styles-admin.css', array(), self::VERSION, 'all' );
$redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' ); $redirect_uri = admin_url( 'admin-ajax.php?action=openid-connect-authorize' );
if ( $this->settings->alternate_redirect_uri ) { if ( $this->settings->alternate_redirect_uri ) {
@ -151,6 +161,7 @@ class OpenID_Connect_Generic {
$this->settings->endpoint_userinfo, $this->settings->endpoint_userinfo,
$this->settings->endpoint_token, $this->settings->endpoint_token,
$redirect_uri, $redirect_uri,
$this->settings->acr_values,
$state_time_limit, $state_time_limit,
$this->logger $this->logger
); );
@ -327,14 +338,15 @@ class OpenID_Connect_Generic {
// Default settings values. // Default settings values.
array( array(
// OAuth client settings. // OAuth client settings.
'login_type' => 'button', 'login_type' => defined( 'OIDC_LOGIN_TYPE' ) ? OIDC_LOGIN_TYPE : 'button',
'client_id' => defined( 'OIDC_CLIENT_ID' ) ? OIDC_CLIENT_ID : '', 'client_id' => defined( 'OIDC_CLIENT_ID' ) ? OIDC_CLIENT_ID : '',
'client_secret' => defined( 'OIDC_CLIENT_SECRET' ) ? OIDC_CLIENT_SECRET : '', 'client_secret' => defined( 'OIDC_CLIENT_SECRET' ) ? OIDC_CLIENT_SECRET : '',
'scope' => '', 'scope' => defined( 'OIDC_CLIENT_SCOPE' ) ? OIDC_CLIENT_SCOPE : '',
'endpoint_login' => defined( 'OIDC_ENDPOINT_LOGIN_URL' ) ? OIDC_ENDPOINT_LOGIN_URL : '', 'endpoint_login' => defined( 'OIDC_ENDPOINT_LOGIN_URL' ) ? OIDC_ENDPOINT_LOGIN_URL : '',
'endpoint_userinfo' => defined( 'OIDC_ENDPOINT_USERINFO_URL' ) ? OIDC_ENDPOINT_USERINFO_URL : '', 'endpoint_userinfo' => defined( 'OIDC_ENDPOINT_USERINFO_URL' ) ? OIDC_ENDPOINT_USERINFO_URL : '',
'endpoint_token' => defined( 'OIDC_ENDPOINT_TOKEN_URL' ) ? OIDC_ENDPOINT_TOKEN_URL : '', 'endpoint_token' => defined( 'OIDC_ENDPOINT_TOKEN_URL' ) ? OIDC_ENDPOINT_TOKEN_URL : '',
'endpoint_end_session' => defined( 'OIDC_ENDPOINT_LOGOUT_URL' ) ? OIDC_ENDPOINT_LOGOUT_URL : '', 'endpoint_end_session' => defined( 'OIDC_ENDPOINT_LOGOUT_URL' ) ? OIDC_ENDPOINT_LOGOUT_URL : '',
'acr_values' => defined( 'OIDC_ACR_VALUES' ) ? OIDC_ACR_VALUES : '',
// Non-standard settings. // Non-standard settings.
'no_sslverify' => 0, 'no_sslverify' => 0,
@ -346,13 +358,13 @@ class OpenID_Connect_Generic {
'identify_with_username' => false, 'identify_with_username' => false,
// Plugin settings. // Plugin settings.
'enforce_privacy' => 0, 'enforce_privacy' => defined( 'OIDC_ENFORCE_PRIVACY' ) ? intval( OIDC_ENFORCE_PRIVACY ) : 0,
'alternate_redirect_uri' => 0, 'alternate_redirect_uri' => 0,
'token_refresh_enable' => 1, 'token_refresh_enable' => 1,
'link_existing_users' => 0, 'link_existing_users' => defined( 'OIDC_LINK_EXISTING_USERS' ) ? intval( OIDC_LINK_EXISTING_USERS ) : 0,
'create_if_does_not_exist' => 1, 'create_if_does_not_exist' => defined( 'OIDC_CREATE_IF_DOES_NOT_EXIST' ) ? intval( OIDC_CREATE_IF_DOES_NOT_EXIST ) : 1,
'redirect_user_back' => 0, 'redirect_user_back' => defined( 'OIDC_REDIRECT_USER_BACK' ) ? intval( OIDC_REDIRECT_USER_BACK ) : 0,
'redirect_on_logout' => 1, 'redirect_on_logout' => defined( 'OIDC_REDIRECT_ON_LOGOUT' ) ? intval( OIDC_REDIRECT_ON_LOGOUT ) : 1,
'enable_logging' => 0, 'enable_logging' => 0,
'log_limit' => 1000, 'log_limit' => 1000,
) )
@ -370,9 +382,24 @@ class OpenID_Connect_Generic {
add_filter( 'the_excerpt_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 ); add_filter( 'the_excerpt_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 );
add_filter( 'comment_text_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 ); add_filter( 'comment_text_rss', array( $plugin, 'enforce_privacy_feeds' ), 999 );
} }
/**
* Create (if needed) and return a singleton of self.
*
* @return OpenID_Connect_Generic
*/
public static function instance() {
if ( null === self::$_instance ) {
self::bootstrap();
}
return self::$_instance;
}
} }
OpenID_Connect_Generic::bootstrap(); OpenID_Connect_Generic::instance();
register_activation_hook( __FILE__, array( 'OpenID_Connect_Generic', 'activation' ) ); register_activation_hook( __FILE__, array( 'OpenID_Connect_Generic', 'activation' ) );
register_deactivation_hook( __FILE__, array( 'OpenID_Connect_Generic', 'deactivation' ) ); register_deactivation_hook( __FILE__, array( 'OpenID_Connect_Generic', 'deactivation' ) );
// Provide publicly accessible plugin helper functions.
require_once( 'includes/functions.php' );

41001
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{ {
"name": "openid-connect-generic", "name": "openid-connect-generic",
"version": "3.8.5", "version": "3.9.0",
"description": "OpenID Connect generic WordPress plugin.", "description": "OpenID Connect generic WordPress plugin.",
"main": "Gruntfile.js", "main": "Gruntfile.js",
"repository": { "repository": {
@ -21,16 +21,16 @@
"dev-require": "^0.1.0" "dev-require": "^0.1.0"
}, },
"engines": { "engines": {
"node": "12.18.3", "node": "14.18.3",
"npm": "6.14.8" "npm": "6.14.15"
}, },
"devDependencies": { "devDependencies": {
"@floatwork/grunt-po2mo": "^0.3.0", "@floatwork/grunt-po2mo": "^0.3.0",
"@ndigitals/grunt-checkrepo": "^0.2.0", "@ndigitals/grunt-checkrepo": "0.2.3",
"@wordpress/env": "~4.0.0", "@wordpress/env": "4.3.1",
"@wordpress/scripts": "12.6.1", "@wordpress/scripts": "22.2.1",
"check-node-version": "~4.1.0", "check-node-version": "~4.1.0",
"grunt": "1.3.0", "grunt": "1.4.1",
"grunt-checkbranch": "^1.0.4", "grunt-checkbranch": "^1.0.4",
"grunt-checktextdomain": "^1.0.1", "grunt-checktextdomain": "^1.0.1",
"grunt-cli": "1.4.1", "grunt-cli": "1.4.1",
@ -38,27 +38,30 @@
"grunt-contrib-copy": "^1.0.0", "grunt-contrib-copy": "^1.0.0",
"grunt-gitinfo": "^0.1.9", "grunt-gitinfo": "^0.1.9",
"grunt-shell": "^2.1.0", "grunt-shell": "^2.1.0",
"grunt-version": "~2.0.0", "grunt-version": "3.0.0",
"grunt-wp-i18n": "^1.0.3", "grunt-wp-i18n": "^1.0.3",
"grunt-wp-readme-to-markdown": "^2.0.0", "grunt-wp-readme-to-markdown": "2.1.0",
"load-grunt-tasks": "^3.5", "load-grunt-tasks": "^3.5",
"node": "^12.21.0", "node": "14.18.3",
"npm": "6.14.12", "npm": "6.14.15",
"puppeteer": "^1.20.0", "puppeteer": "^1.20.0",
"typescript": "~3.9.9" "typescript": "3.9.10"
},
"resolutions": {
"getobject": "1.0.0",
"shelljs": "0.8.5"
}, },
"wp-env": { "wp-env": {
"plugin-dir": "daggerhart-openid-connect-generic", "plugin-dir": "daggerhart-openid-connect-generic",
"plugin-name": "OpenID Connect Generic", "plugin-name": "OpenID Connect Generic",
"docker-template": "./docker-compose.override.yml", "docker-template": "./docker-compose.wp-env.yml",
"welcome-build-command": "npm start" "welcome-build-command": "npm start"
}, },
"scripts": { "scripts": {
"setup": "npm run setup:npm && npm run setup:composer && npm run build:wordpress", "preinstall": "npx force-resolutions",
"setup:npm": "npm install", "setup:composer": "docker-compose run composer install",
"setup:composer": "composer install", "composer": "docker-compose run composer",
"build": "npm run grunt build", "build": "npm run grunt build",
"build:wordpress": "cd wordpress && npm install && npm run build && cd .. && composer install --optimize-autoloader",
"release": "npm run grunt release", "release": "npm run grunt release",
"start": "wp-env start", "start": "wp-env start",
"stop": "wp-env stop", "stop": "wp-env stop",
@ -76,9 +79,9 @@
"i18n:make": "npm run grunt i18n", "i18n:make": "npm run grunt i18n",
"i18n:make:cli": "wp-env run cli wp i18n make-pot . languages/ --slug=daggerhart-openid-connect-generic --include=openid-connect-generic.php,includes", "i18n:make:cli": "wp-env run cli wp i18n make-pot . languages/ --slug=daggerhart-openid-connect-generic --include=openid-connect-generic.php,includes",
"lint": "npm run lint:php", "lint": "npm run lint:php",
"lint:php": "composer run-script lint", "lint:php": "docker-compose run composer lint",
"lint:php:fix": "composer run-script lint-fix", "lint:php:fix": "docker-compose run composer lint-fix",
"analyze": "npm run analyze:php", "analyze": "npm run analyze:php",
"analyze:php": "composer run-script analyze" "analyze:php": "docker-compose run composer analyze"
} }
} }

@ -113,6 +113,6 @@
############################################################################# #############################################################################
--> -->
<config name="testVersion" value="7.3-"/> <config name="testVersion" value="7.4-"/>
<rule ref="PHPCompatibilityWP" /> <rule ref="PHPCompatibilityWP" />
</ruleset> </ruleset>

@ -23,7 +23,7 @@ parameters:
paths: paths:
- includes/ - includes/
- ./ - ./
excludes_analyse: excludePaths:
- node_modules/ - node_modules/
- scripts/ - scripts/
- tests/ - tests/
@ -33,7 +33,7 @@ parameters:
# scanFiles: # scanFiles:
# - includes/class.php # - includes/class.php
scanDirectories: scanDirectories:
- wordpress/src/ - wordpress
ignoreErrors: ignoreErrors:
# Uses func_get_args() # Uses func_get_args()
- '#^Function apply_filters(_ref_array)? invoked with [34567] parameters, 2 required\.$#' - '#^Function apply_filters(_ref_array)? invoked with [34567] parameters, 2 required\.$#'

@ -3,9 +3,9 @@ Contributors: daggerhart, tnolte
Donate link: http://www.daggerhart.com/ Donate link: http://www.daggerhart.com/
Tags: security, login, oauth2, openidconnect, apps, authentication, autologin, sso Tags: security, login, oauth2, openidconnect, apps, authentication, autologin, sso
Requires at least: 4.9 Requires at least: 4.9
Tested up to: 5.7.1 Tested up to: 5.9.2
Stable tag: 3.8.5 Stable tag: 3.9.0
Requires PHP: 7.1 Requires PHP: 7.2
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html License URI: http://www.gnu.org/licenses/gpl-2.0.html
@ -51,11 +51,29 @@ On the settings page for this plugin (Dashboard > Settings > OpenID Connect Gene
== Changelog == == Changelog ==
= 3.8.5 = 3.9.0 =
* Fix: @timnolte - Fixes missing URL request validation before use & ensure proper current page URL is setup for Redirect Back. * Feature: @matchaxnb - Added support for additional configuration constants.
* Fix: @timnolte - Fixes Redirect URL Logic to Handle Sub-directory Installs. * Feature: @schanzen - Added support for agregated claims.
* Fix: @timnolte - Fixes to provide proper redirect user back for the openid_connect_generic_auth_url shortcode. * Fix: @rkcreation - Fixed access token not updating user metadata after login.
* Fix: @danc1248 - Fixed user creation issue on Multisite Networks.
* Feature: @RobjS - Added plugin singleton to support for more developer customization.
* Feature: @jkouris - Added action hook to allow custom handling of session expiration.
* Fix: @tommcc - Fixed admin CSS loading only on the plugin settings screen.
* Feature: @rkcreation - Added method to refresh the user claim.
* Feature: @Glowsome - Added acr_values support & verification checks that it when defined in options is honored.
* Fix: @timnolte - Fixed regression which caused improper fallback on missing claims.
* Fix: @slykar - Fixed missing query string handling in redirect URL.
* Fix: @timnolte - Fixed issue with some user linking and user creation handling.
* Improvement: @timnolte - Fixed plugin settings typos and screen formatting.
* Security: @timnolte - Updated build tooling security vulnerabilities.
* Improvement: @timnolte - Changed build tooling scripts.
= 3.8.5 =
* Fix: @timnolte - Fixed missing URL request validation before use & ensure proper current page URL is setup for Redirect Back.
* Fix: @timnolte - Fixed Redirect URL Logic to Handle Sub-directory Installs.
* Fix: @timnolte - Fixed issue with redirecting user back when the openid_connect_generic_auth_url shortcode is used.
= 3.8.4 = = 3.8.4 =

@ -23,3 +23,10 @@ defined( 'OIDC_ENDPOINT_LOGIN_URL' ) || define( 'OIDC_ENDPOINT_LOGIN_URL', 'http
defined( 'OIDC_ENDPOINT_USERINFO_URL' ) || define( 'OIDC_ENDPOINT_USERINFO_URL', 'https://oidc/oauth2/userinfo' ); defined( 'OIDC_ENDPOINT_USERINFO_URL' ) || define( 'OIDC_ENDPOINT_USERINFO_URL', 'https://oidc/oauth2/userinfo' );
defined( 'OIDC_ENDPOINT_TOKEN_URL' ) || define( 'OIDC_ENDPOINT_TOKEN_URL', 'https://oidc/oauth2/token' ); defined( 'OIDC_ENDPOINT_TOKEN_URL' ) || define( 'OIDC_ENDPOINT_TOKEN_URL', 'https://oidc/oauth2/token' );
defined( 'OIDC_ENDPOINT_LOGOUT_URL' ) || define( 'OIDC_ENDPOINT_LOGOUT_URL', 'https://oidc/oauth2/logout' ); defined( 'OIDC_ENDPOINT_LOGOUT_URL' ) || define( 'OIDC_ENDPOINT_LOGOUT_URL', 'https://oidc/oauth2/logout' );
defined( 'OIDC_CLIENT_SCOPE' ) || define( 'OIDC_CLIENT_SCOPE', 'email profile openid' );
defined( 'OIDC_LOGIN_TYPE' ) || define( 'OIDC_LOGIN_TYPE', 'button' );
defined( 'OIDC_LINK_EXISTING_USERS' ) || define( 'OIDC_LINK_EXISTING_USERS', 0 );
defined( 'OIDC_ENFORCE_PRIVACY' ) || define( 'OIDC_ENFORCE_PRIVACY', 0 );
defined( 'OIDC_CREATE_IF_DOES_NOT_EXIST' ) || define( 'OIDC_CREATE_IF_DOES_NOT_EXIST', 1 );
defined( 'OIDC_REDIRECT_USER_BACK' ) || define( 'OIDC_REDIRECT_USER_BACK', 0 );
defined( 'OIDC_REDIRECT_ON_LOGOUT' ) || define( 'OIDC_REDIRECT_ON_LOGOUT', 1 );

@ -0,0 +1,20 @@
# Start with the official PHP CLI image.
FROM php:7.4-cli
# Increase the memory limit to allow for large processes, such as PHPStan.
RUN cd /usr/local/etc/php/conf.d/ && \
echo 'memory_limit = -1' >> /usr/local/etc/php/conf.d/docker-php-ram-limit.ini
# Copy the Composer PHAR from the official Composer image to the PHP CLI image.
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# Install additional packages required for Composer
RUN apt-get update \
&& apt-get install -y git zip unzip zlib1g-dev libzip-dev \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN docker-php-ext-install zip \
&& docker-php-ext-install pcntl \
&& docker-php-ext-install bcmath
Loading…
Cancel
Save