<?php
namespace App\Controller;
use Alancting\Microsoft\JWT\AzureAd\AzureAdConfiguration;
use Alancting\Microsoft\JWT\AzureAd\AzureAdIdTokenJWT;
use Firebase\JWT\JWT;
use League\OAuth2\Client\Provider\GenericProvider;
use PhpParser\Comment\Doc;
use Pimcore\Controller\FrontendController;
use Pimcore\Model\DataObject\Account;
use Pimcore\Model\DataObject\Manager;
use Pimcore\Model\Document;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\String\ByteString;
use Pimcore\Cache;
class SsoController extends FrontendController
{
/**
* 跳转逻辑
* wcmManage: /sso/webLogin?app=wcm&usr=luy56&path=https://oneportalstg.medtronic.com.cn/#/login
* @Route("/sso/webLogin")
* @return
*/
public function webLoginAction(Request $request) {
$app= $request->get('app');
$networkId= $request->get('usr');
$code=uniqid('em',true);
$account = Account::getByNetworkId($networkId, 1);
if(!$account) {
$data = [
'error'=>'登录成功但用户不存在',
'errorDetail'=>'用户邮箱不存在,请先添加用户至wcm后台'
];
return $this->render('default/msg.html.twig', $data);
}
$data = [
'userId'=>$account->getNetworkId(),
'email'=>$account->getEmail(),
'displayName'=>$account->getName(),
];
Cache::save($data,$code,[],120);
$path="https://oneportalstg.medtronic.com.cn/#/login";
if($app="crdn_sales"){
$path="https://education-stag.medtronic-digital.com/crdn_sales/login";
}
return $this->redirect($path.'?code='.$code);
}
/**
* 微软sso登录
* ESign: /sso/login?app=esign
* wcmAR: /sso/login?app=arsp
* wcmManage: /sso/login?app=wcm
* @Route("/sso/login")
* @return
*/
public function loginAction(Request $request) {
// Initialize the OAuth client
$oauthClient = new GenericProvider([
'clientId' => OAUTH_APP_ID,
'clientSecret' => OAUTH_APP_SECRET,
'redirectUri' => OAUTH_REDIRECT_URI,
'urlAuthorize' => OAUTH_AUTHORITY.OAUTH_AUTHORIZE_ENDPOINT,
'urlAccessToken' => OAUTH_AUTHORITY.OAUTH_TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => '',
'scopes' => OAUTH_SCOPES
]);
$authUrl = $oauthClient->getAuthorizationUrl();
// $session = $request->getSession();
// $session->set('app', $request->get('app'));
// $session->set('oauthState', $oauthClient->getState());
setcookie('app', $request->get('app'));
$app= $request->get('app');
$state=$oauthClient->getState();
setcookie('oauthState'.'_'.$state, $oauthClient->getState());
//2024-11-11 path parameter add.
$path= $request->get('path');
if(isset($path)){
setcookie('oauthPath'.'_'.$state,$path);
}else{
setcookie('oauthPath'.'_'.$state,"demo");
}
setcookie($state,$request->get('app'));//新增state对应App,用于反向查找App,用于验证浏览器端存储的state是否正确。
// $data = [
// 'redirectUrl' => $authUrl,
// 'error' =>'<img src="/img/load.gif" loading="lazy" alt="" class="load-img">',
// 'errorDetail' => '正在加载登录页面,请稍等...'
// ];
// return $this->render('default/msg.html.twig', $data);
return $this->redirect($authUrl); // 进入微软登录
}
/**
* 微软sso登录重定向
* @Route("/sso/callback")
* @return
*/
public function callbackAction(Request $request)
{
$session = $request->getSession();
$state=$request->get('state');
$app = $_COOKIE[$state];//获取state对应App。
$path= $_COOKIE['oauthPath'.'_'.$state];//2024-11-11
$oauthState = $_COOKIE['oauthState'.'_'.$state];//获取App对应State;
setcookie($state,'',time()-60);//清理Cookie App
setcookie('oauthState'.'_'.$state,'',time()-60);//清理Cookie State
if(!$oauthState) {
$redirectUrl = '/sso/login?app='.$app;
$data = [
'redirectUrl' => $redirectUrl,
'error' => '重定向!',
'errorDetail' => '正在重新登录应用!'
];
return $this->render('default/msg.html.twig', $data);
} else {
$code = $request->get('code');
$state = $request->get('state');
if (empty($state)) {
$data = [
'error'=>'no state',
'errorDetail'=>'there is no expected state in the session'
];
return $this->render('default/msg.html.twig', $data);
}
if ($state != $oauthState) {
$data = [
'error'=>'Invalid auth state',
'errorDetail'=>'The provided auth state did not match the expected value. '.$state.' , '.$oauthState
];
//ApplicationLogger::getInstance()->info('SSO State'.$state.' '.$oauthState);
return $this->render('default/msg.html.twig', $data);
}
$redirectUrl = '/sso/redirectUrl?code='.$code;
$kname=md5($code);
//2024-11-11 added path;
$kpath='path'.'_'.$kname;
setcookie($kpath,$path);
setcookie($kname,$app);//新增Code对应App,用于反向查找App
}
$data = [
'redirectUrl' => $redirectUrl,
'error' => '登录成功!',
'errorDetail' => '正在验证用户信息'
];
return $this->render('default/msg.html.twig', $data);
}
/**
* 内部跳转一次,使session生效
* @Route("/sso/redirectUrl")
* @return
*/
public function redirectUrlAction(Request $request) {
$session = $request->getSession();
$authCode = $request->get('code');
$kname=md5($authCode);
//2024-11-11 added path
$kpath='path'.'_'.$kname;
$path =$_COOKIE[$kpath];
$app = $_COOKIE[$kname];//更新为code绑定App。
setcookie($kname,'',time()-60);
// Authorization code should be in the "code" query param
if (!empty($authCode)) {
$oauthParams = [
'client_id' => OAUTH_APP_ID,
'client_secret' => OAUTH_APP_SECRET,
'redirect_uri' => OAUTH_REDIRECT_URI,
'urlAuthorize' => OAUTH_AUTHORITY.OAUTH_AUTHORIZE_ENDPOINT,
'urlAccessToken' => OAUTH_AUTHORITY.OAUTH_TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => '',
'scopes' => OAUTH_SCOPES
];
// Initialize the OAuth client
//$oauthClient = new GenericProvider($oauthParams);
try {
// Make the token request
//$accessToken = $oauthClient->getAccessToken('authorization_code', [
// 'code' => $authCode
//]);
$authData = $this->reqData('post', OAUTH_AUTHORITY.OAUTH_TOKEN_ENDPOINT, array_merge($oauthParams, [
'grant_type'=>'authorization_code',
'code'=>$authCode
]));
//var_dump($authData);
$access_token = $authData['access_token'];
$id_token = $authData['id_token'];
// var_dump($authData);
// echo "</br>";
// var_dump($id_token);
// die();
$config_options = [
'tenant' => OAUTH_TENANT_ID,
'tenant_id' => OAUTH_TENANT_ID, // 租户id
'client_id' => OAUTH_APP_ID, // appid
'config_uri' => OAUTH_AUTHORITY.'/v2.0/.well-known/openid-configuration?appid='.OAUTH_APP_ID, // appid
'idTokenCheck' => true
];
$config = new AzureAdConfiguration($config_options);
$id_token_jwt = new AzureAdIdTokenJWT($config, $id_token);
// print_r($id_token_jwt->getPayload());
// print_r($id_token_jwt->get('email'));
if($id_token_jwt->isExpired()) {
$data = [
'error'=>'Access failed',
'errorDetail'=>'id token 过期'
];
return $this->render('default/msg.html.twig', $data);
}
// 解析邮箱
$arr = explode('.', $access_token);
$jsonData = JWT::urlsafeB64Decode($arr[1]);
$userInfo = json_decode($jsonData, true);
$email = $userInfo['upn'];//20250417 Modify to networkid to fix the IAM team's change
$networkId = substr($email, 0, stripos($email, '@'));
$azureCode = ByteString::fromRandom(32);
if($app=='wcm') {
$manager = Manager::getByAccount($email, 1);
if(!$manager) {
$data = [
'error'=>'无权访问',
'errorDetail'=>'管理员邮箱不存在'
];
return $this->render('default/sso.html.twig', $data);
}
$manager->setSsoCode($azureCode);
$manager->setPublished(true);
$manager->save();
return $this->redirect(ADMIN_DOMAIN.'#/login?code='.$azureCode);
}elseif($app=='oneportal'){
$code=uniqid('em',true);
Cache::save($jsonData,$code,[],120);
return $this->redirect('https://oneportalstg.medtronic.com.cn/#/login?code='.$code.'&user='.$jsonData);
}elseif($app=='university'){
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://university.medtronic.com.cn/mdtuniversity/login'.'?code='.$code);
}elseif($app=='academy'){
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://ma-wstag.medtronic.com.cn/login'.'?code='.$code);
}elseif($app=='shapde_apv_academy_admin'){//2024-11-11
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://me.workatall.com/apv-lm/admin?role=admin&'.'code='.$code);
}elseif($app=='shapde_apv_ academy _sales'){
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://me.workatall.com/apv-lm/login?role=sales&'.'code='.$code);
}elseif($app=='ent_da_sales'){
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://me.workatall.com/entda/login'.'?code='.$code);
}elseif($app=='shape_pvh_da_sales'){
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://me.workatall.com/pvh/login'.'?code='.$code);
}elseif($app=='shape_pvh_static_sales'){
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://me.workatall.com/pvh_static/login'.'?code='.$code);
}elseif($app=='ns_csf_da_ sales'){//2024-11-11
$code=uniqid('em',true);
$data = [
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect('https://me.workatall.com/csf/login'.'?code='.$code);
}elseif($app=='rdn'){
$code=uniqid('em',true);
$data = [
'app'=>$app,
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name']
];
Cache::save($data,$code,[],120);
return $this->redirect(APP_DOMAIN.'#/login?code='.$code);
}else {
$account = Account::getByNetworkId($networkId, 1);
if(!$account) {
$data = [
'error'=>'登录成功但用户不存在',
'errorDetail'=>'用户邮箱不存在,请先添加用户至wcm后台'
];
return $this->render('default/msg.html.twig', $data);
}
if($app=='arsp') {
$account->setAzureCode($azureCode);
$account->setPublished(true);
$account->save();
$data = [
'email'=>$email,
'code'=>$azureCode,
'domain'=>APP_DOMAIN,
'error'=>'登录成功!',
'errorDetail'=>'即将跳转至APP'
];
return $this->render('default/sso.html.twig', $data);
} elseif($app=='esign') {
if ($account->getisLogin() != 1) {
return $this->render('esign/message.html.twig', ['message' => '无登录权限']);
}
$admin = [
'id' => $account->getId(),
'account' => $account->getEmail(),
'isRemove' => $account->getIsRemove(),
'isLogin' => $account->getIsLogin(),
'userType' => 'eSign',
];
$session->set('admin', $admin);
return $this->redirect('/esign/inquire');
}elseif($app=='ehs') {
if ($account->getEHSisLogin() != 1) {
return $this->render('esign/message.html.twig', ['message' => '无登录权限']);
}
$admin = [
'id' => $account->getId(),
'account' => $account->getEmail(),
'isRemove' => $account->getEHSIsRemove(),
'isLogin' => $account->getEHSIsLogin(),
'userType' => 'ehs',
];
$session->set('admin', $admin);
return $this->redirect('/ehs/inquire');
}elseif($app=='compliance') {
if ($account->getcomplianceIsLogin() != 1) {
return $this->render('esign/message.html.twig', ['message' => '无登录权限']);
}
$admin = [
'id' => $account->getId(),
'account' => $account->getEmail(),
'isRemove' => $account->getcomplianceIsRemove(),
'isLogin' => $account->getcomplianceIsLogin(),
'userType' => 'compliance',
];
$session->set('admin', $admin);
return $this->redirect('/compliance/inquire');
}elseif($app=='carelink') {
if ($account->getcarelinkIsLogin() != 1) {
return $this->render('carelink/message.html.twig', ['message' => '无Carelink From App登录权限']);
}
$account->setcarelinkToken($azureCode);
$account->setPublished(true);
$account->save();
$admin = [
'id' => $account->getId(),
'account' => $account->getEmail(),
'isLogin' => $account->getcarelinkIsLogin(),
'userType' => 'carelink',
'code'=>$azureCode,
];
$session->set('admin', $admin);
return $this->redirect('/carelink/inquire');
}else{//2024-11-11 added
$code=uniqid('em',true);
$usr=explode('@',$userInfo['unique_name']);
$data = [
'app'=>$app,
'userId'=>$networkId,
'email'=>$userInfo['unique_name'],
'displayName'=>$userInfo['name'],
];
Cache::save($data,$code,[],120);
return $this->redirect($path.'?code='.$code);
}
}
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
$data = [
'error'=>'Error requesting access token',
'errorDetail'=>json_encode($e->getResponseBody())
];
return $this->render('default/sso.html.twig', $data);
}
}
$data = [
'error'=>$request->get('error'),
'errorDetail'=>$request->get('error_description')
];
return $this->render('default/msg.html.twig', $data);
}
/**
* 退出
* @Route("/sso/logout")
* @return
*/
public function logoutAction(Request $request) {
$params = $request->query->all();
$data = [
'error'=>'Logout',
'errorDetail'=>'已退出'
];
return $this->render('default/msg.html.twig', $data);
}
public function reqData($method, $url, $data=[], $headers=[]) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_PROXY,MDT_CURL_PROXY);
$data = http_build_query($data);
if($method=='get') {
curl_setopt($ch, CURLOPT_POST, 0);
$url .= '?'.$data;
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_POST, 1);
}
curl_setopt($ch, CURLOPT_URL, $url);
$output = curl_exec($ch);
$curl_info = curl_getinfo($ch);
//var_dump($curl_info);
//var_dump($output);
curl_close($ch);
return json_decode($output, true);
}
/**
* 根据code获取sso user
* @Route("/sso/getUserByCode")
* @return
*/
public function getUserByCodeAction(Request $request) {
header("Cache-Control: no-cached");
header("Access-Control-Allow-Credentials:true");
header("Content-Type: */*");
header("Access-Control-Allow-Headers: *");
header("Access-Control-Allow-Origin: *");
$code = $request->query->get('code');
$user = Cache::load($code);//2分钟销毁
return $this->json($user);
}
}