Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReClique SSO Integration in openy_gc_auth_reclique_sso module #254

Merged
merged 8 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions modules/openy_gc_auth/modules/openy_gc_auth_reclique_sso/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## About
The goal of this module is to give ability
to log into Vitrual Y using OAuth2 protocol, in case if your CRM is Reclique.

## How to use this integration.

1. Enable this module.
2. Setup your Reclique SSO OAuth2 credentials
here: /admin/openy/virtual-ymca/gc-auth-settings/provider/reclique_sso
3. Set Reclique SSO OAuth2 as your main authorization plugin
at the Virtual YMCA settings: /admin/openy/openy-gc-auth/settings

## I need help.
In case, if you need help, please write your question
at the #developers channel at Open Y slack.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
authorization_server: 'https://[association_slug].recliquecore.com'
client_id: ''
client_secret: ''
error_accompanying_message: 'Please contact us if you have any questions.'
login_mode: 'present_login_button'
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: Reclique SSO OAuth2 Virtual YMCA integration
type: module
description: 'Provides Reclique SSO OAuth2 authentication plugin for Virtual YMCA'
package: Open Y Virtual YMCA
version: 0.1
core: 8.x
core_version_requirement: ^8 || ^9
dependencies:
- drupal:openy_gc_auth
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* @file
* Main file for openy_gc_auth_reclique_sso module.
*/

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;

/**
* Implements hook_entity_view().
*/
function openy_gc_auth_reclique_sso_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
$bundle = $entity->bundle();
if ($bundle === 'gated_content_login') {
$build['#cache']['max-age'] = 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
openy_gc_auth_reclique_sso.authenticate_redirect:
path: '/openy-gc-auth-reclique-sso/authenticate-redirect'
defaults:
_controller: '\Drupal\openy_gc_auth_reclique_sso\Controller\SSOController::authenticateRedirect'
_title: 'Reclique SSO OAuth2 authenticate redirect'
requirements:
_permission: 'access content'
options:
no_cache: 'TRUE'

openy_gc_auth_reclique_sso.authenticate_callback:
path: '/openy-gc-auth-reclique-sso/authenticate-callback'
defaults:
_controller: '\Drupal\openy_gc_auth_reclique_sso\Controller\SSOController::authenticateCallback'
_title: 'Reclique SSO OAuth2 authenticate callback'
requirements:
_permission: 'access content'
options:
no_cache: 'TRUE'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
services:
openy_gc_auth.reclique_sso_client:
class: Drupal\openy_gc_auth_reclique_sso\SSOClient
arguments: [ '@logger.factory', '@config.factory',
'@http_client', '@csrf_token',
'@user.private_tempstore' ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php

namespace Drupal\openy_gc_auth_reclique_sso\Controller;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Url;
use Drupal\openy_gc_auth_reclique_sso\SSOClient;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\openy_gc_auth\GCUserAuthorizer;

/**
* Class with controller endpoints, needed for reclique_sso plugin.
*/
class SSOController extends ControllerBase {

/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;

/**
* Config for openy_gated_content module.
*
* @var \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
*/
protected $configOpenyGatedContent;

/**
* The Gated Content User Authorizer.
*
* @var \Drupal\openy_gc_auth\GCUserAuthorizer
*/
protected $gcUserAuthorizer;

/**
* Reclique SSO OAuth2 client.
*
* @var \Drupal\openy_gc_auth_reclique_sso\SSOClient
*/
protected $recliqueSSOClient;

/**
* SSOController constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* Config factory instance.
* @param \Drupal\openy_gc_auth\GCUserAuthorizer $gcUserAuthorizer
* The Gated User Authorizer.
* @param \Drupal\openy_gc_auth_reclique_sso\SSOClient $recliqueSSOClient
* Reclique SSO OAuth2 Client.
*/
public function __construct(
ConfigFactoryInterface $configFactory,
GCUserAuthorizer $gcUserAuthorizer,
SSOClient $recliqueSSOClient
) {
$this->configFactory = $configFactory;
$this->configOpenyGatedContent = $configFactory->get('openy_gated_content.settings');
$this->gcUserAuthorizer = $gcUserAuthorizer;
$this->recliqueSSOClient = $recliqueSSOClient;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('openy_gc_auth.user_authorizer'),
$container->get('openy_gc_auth.reclique_sso_client')
);
}

/**
* Redirect, login user and return authorization code.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* Current request object.
*
* @return \Drupal\Core\Routing\TrustedRedirectResponse
* Redirect to the Reclique login page.
*/
public function authenticateRedirect(Request $request): TrustedRedirectResponse {
if (!empty($this->response)) {
return $this->response;
}

$oAuth2AuthenticateUrl = $this->recliqueSSOClient->buildAuthenticationUrl($request);
$this->response = new TrustedRedirectResponse($oAuth2AuthenticateUrl);
$this->response->addCacheableDependency((new CacheableMetadata())->setCacheMaxAge(0));
return $this->response;
}

/**
* Receive authorization code, load user data and authorize user.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* Current request object.
*
* @return mixed
* Returns RedirectResponse or JsonResponse.
*/
public function authenticateCallback(Request $request) {
// Check code that was generated by Open Y.
if (!$this->recliqueSSOClient->validateCsrfToken($request->get('state'))) {
return new RedirectResponse(
URL::fromUserInput(
$this->configOpenyGatedContent->get('virtual_y_login_url'),
['query' => ['error' => '1']]
)->toString()
);
}

$access_token = $this->recliqueSSOClient->exchangeCodeForAccessToken($request->get('code'));

if (!$access_token) {
return new RedirectResponse(
URL::fromUserInput(
$this->configOpenyGatedContent->get('virtual_y_login_url'),
['query' => ['error' => '1']]
)->toString()
);
}

$userData = $this->recliqueSSOClient->requestUserData($access_token);

if (!$userData) {
return new RedirectResponse(
URL::fromUserInput(
$this->configOpenyGatedContent->get('virtual_y_login_url'),
['query' => ['error' => '1']]
)->toString()
);
}

if ($this->recliqueSSOClient->validateUserSubscription($userData)) {
[$name, $email] = $this->recliqueSSOClient
->prepareUserNameAndEmail($userData);

// Authorize user (register, login, log, etc).
$this->gcUserAuthorizer->authorizeUser($name, $email);

return new RedirectResponse($this->configOpenyGatedContent->get('virtual_y_url'));
}

// Redirect back to Virual Y login page.
return new RedirectResponse(
URL::fromUserInput(
$this->configOpenyGatedContent->get('virtual_y_login_url'),
['query' => ['error' => '1']]
)->toString()
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Drupal\openy_gc_auth_reclique_sso\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;

/**
* Build button which provides authentication through Reclique CRM.
*
* @package Drupal\openy_gc_auth_reclique_sso\Form
*/
class ContinueWithRecliqueLoginForm extends FormBase {

use StringTranslationTrait;

/**
* {@inheritdoc}
*/
public function getFormId() {
return 'openy_gc_auth_reclique_sso_login_form';
}

/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['submit'] = [
'#type' => 'link',
'#url' => Url::fromRoute('openy_gc_auth_reclique_sso.authenticate_redirect'),
'#title' => $this->t('Enter Virtual Y'),
'#attributes' => [
'class' => [
'gc-button',
],
],
];

$form['#attributes'] = [
'class' => 'text-center',
];

return $form;
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$form_state->setRedirectUrl(Url::fromRoute('openy_gc_auth_reclique_sso.authenticate_redirect'));
}

}
Loading