博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
azure web应用部署_Java Web应用程序中的Azure AD SSO,ADFS SSO配置
阅读量:2532 次
发布时间:2019-05-11

本文共 15174 字,大约阅读时间需要 50 分钟。

azure web应用部署

Azure AD单点登录 (Azure AD SSO)

The Single Sign-On feature is getting popular among developers to handle Application Access Management while developing multi-faced applications due to its remarkable advantages. Azure Active Directory is one of the most popular solutions used for Directory Management, Application Access Management and secured Identity Management, which offers the efficient Single Sign-On feature as well.

单点登录功能因其显着的优势而在开发多面应用程序的同时,在处理应用程序访问管理的开发人员中越来越受欢迎。 Azure Active Directory是用于目录管理,应用程序访问管理和安全的身份管理的最受欢迎的解决方案之一,该解决方案还提供了有效的单一登录功能。

Recently, I integrated Azure AD SSO with a along with synchronizing it with existing Identity Management system. I used Active Directory Federation Services ADFS 2016. In this blog, I am sharing the integration process in three sections.

最近,我将Azure AD SSO与集成在一起,并将其与现有的Identity Management系统同步。 我使用Active Directory联合身份验证服务ADFS2016。在此博客中,我将在三个部分中共享集成过程。

  1. How to register Java Application in Azure AD

    如何在Azure AD中注册Java应用程序
  2. How to implement ADAL Library in Java Application

    如何在Java应用程序中实现ADAL库
  3. ADFS Configuration for Single Sign-On SSO

    单点登录SSO的ADFS配置

如何在Azure AD中注册Java应用程序 (How to Register Java Application in Azure AD)

Follow the instructions given in the link below to register the Java Application with Azure AD using Active Directory Authentication Library for Java (ADAL4J) and to acquire JWT access token.

请按照下面的链接中给出的说明,使用Java Active Directory身份验证库(ADAL4J)向Azure AD注册Java应用程序,并获取JWT访问令牌。

如何在Java Web应用程序中实现ADAL库 (How to implement ADAL library in Java Web Application)

The process of implementing ADAL Library in Java Application is comprised of total six steps:

在Java应用程序中实现ADAL库的过程总共包括六个步骤:

  1. Add ADAL Library Dependencies

    添加ADAL库依赖关系
  2. Register ADALFilter and add context parameters in your web.xml (Informing the Java App about Azure App configuration)

    注册ADALFilter并在web.xml中添加上下文参数(向Java App通知Azure App配置)
  3. Create AdalFilter

    创建AdalFilter
  4. Create the secure controller

    创建安全控制器
  5. Create AuthHelper class

    创建AuthHelper类
  6. Create aad.jsp

    创建一个aad.jsp

将adal库依赖项添加到Java应用程序 (Add adal library dependencies to the java application)

com.microsoft.azure
adal4j
1.1.1
com.nimbusds
oauth2-oidc-sdk
4.5

注册ADALFilter并在web.xml中添加上下文参数 (Register ADALFilter and add context parameters in your web.xml)

authority
https://login.windows.net/
tenant
YOUR_TENANT_NAME
AdalFilter
com.azilen.aad.AdalFilter
client_id
secret_key
AdalFilter
/secure/*

Replace values of following with actual that you got from Azure portal while registering your application as described in the previous step.

按照上一步中的说明,在注册应用程序时将以下值替换为从Azure门户获得的实际值。

YOUR-CLIENT-ID and YOUR-SECRET-KEY, authority (is your azure ad’s login page), YOUR_TENANT_NAME is the organization name.

YOUR-CLIENT-ID和YOUR-SECRET-KEY(授权)(是您的天蓝色广告的登录页面),YOUR_TENANT_NAME是组织名称。

创建AdalFilter (Create AdalFilter)

AdalFilter checks if current session has valid PRINCIPAL_SESSION_NAME stored, if not then it will redirect to Azure login page (Authority).

AdalFilter将检查当前会话是否存储了有效的PRINCIPAL_SESSION_NAME ,否则将重定向到Azure登录页面(Authority)。

public class AdalFilter implements Filter {	private String clientId = "";	private String clientSecret = "";	private String tenant = "";	private String authority;	public void destroy() {	}	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {		if (request instanceof HttpServletRequest) {			HttpServletRequest httpRequest = (HttpServletRequest) request;			HttpServletResponse httpResponse = (HttpServletResponse) response;			try {				String currentUri = request.getScheme() + "://" + request.getServerName()						+ ("http".equals(request.getScheme()) && request.getServerPort() == 80								|| "https".equals(request.getScheme()) && request.getServerPort() == 443 ? "" : ":" + request.getServerPort())						+ httpRequest.getRequestURI();				String fullUrl = currentUri + (httpRequest.getQueryString() != null ? "?" + httpRequest.getQueryString() : "");				// check if user has a session				if (!AuthHelper.isAuthenticated(httpRequest)) {					if (AuthHelper.containsAuthenticationData(httpRequest)) {						Map
params = new HashMap
(); for (String key : request.getParameterMap().keySet()) { params.put(key, request.getParameterMap().get(key)[0]); } AuthenticationResponse authResponse = AuthenticationResponseParser.parse(new URI(fullUrl), params); if (AuthHelper.isAuthenticationSuccessful(authResponse)) { AuthenticationSuccessResponse oidcResponse = (AuthenticationSuccessResponse) authResponse; AuthenticationResult result = getAccessToken(oidcResponse.getAuthorizationCode(), currentUri); createSessionPrincipal(httpRequest, result); } else { AuthenticationErrorResponse oidcResponse = (AuthenticationErrorResponse) authResponse; throw new Exception(String.format("Request for auth code failed: %s - %s", oidcResponse.getErrorObject().getCode(), oidcResponse.getErrorObject().getDescription())); } } else { // not authenticated httpResponse.setStatus(302); httpResponse.sendRedirect(getRedirectUrl(currentUri)); return; } } else { // if authenticated, how to check for valid session? AuthenticationResult result = AuthHelper.getAuthSessionObject(httpRequest); if (httpRequest.getParameter("refresh") != null) { result = getAccessTokenFromRefreshToken(result.getRefreshToken(), currentUri); } else { if (httpRequest.getParameter("cc") != null) { result = getAccessTokenFromClientCredentials(); } else { if (result.getExpiresOnDate().before(new Date())) { result = getAccessTokenFromRefreshToken(result.getRefreshToken(), currentUri); } } } createSessionPrincipal(httpRequest, result); } } catch (Throwable exc) { httpResponse.setStatus(500); request.setAttribute("error", exc.getMessage()); httpResponse.sendRedirect(((HttpServletRequest) request).getContextPath() + "/error.jsp"); } } chain.doFilter(request, response); } private AuthenticationResult getAccessTokenFromClientCredentials() throws Throwable { AuthenticationContext context = null; AuthenticationResult result = null; ExecutorService service = null; try { service = Executors.newFixedThreadPool(1); context = new AuthenticationContext(authority + tenant + "/", true, service); Future
future = context.acquireToken("https://graph.windows.net", new ClientCredential(clientId, clientSecret), null); result = future.get(); } catch (ExecutionException e) { throw e.getCause(); } finally { service.shutdown(); } if (result == null) { throw new ServiceUnavailableException("authentication result was null"); } return result; } private AuthenticationResult getAccessTokenFromRefreshToken(String refreshToken, String currentUri) throws Throwable { AuthenticationContext context = null; AuthenticationResult result = null; ExecutorService service = null; try { service = Executors.newFixedThreadPool(1); context = new AuthenticationContext(authority + tenant + "/", true, service); Future
future = context.acquireTokenByRefreshToken(refreshToken, new ClientCredential(clientId, clientSecret), null, null); result = future.get(); } catch (ExecutionException e) { throw e.getCause(); } finally { service.shutdown(); } if (result == null) { throw new ServiceUnavailableException("authentication result was null"); } return result; } private AuthenticationResult getAccessToken(AuthorizationCode authorizationCode, String currentUri) throws Throwable { String authCode = authorizationCode.getValue(); ClientCredential credential = new ClientCredential(clientId, clientSecret); AuthenticationContext context = null; AuthenticationResult result = null; ExecutorService service = null; try { service = Executors.newFixedThreadPool(1); context = new AuthenticationContext(authority + tenant + "/", true, service); Future
future = context.acquireTokenByAuthorizationCode(authCode, new URI(currentUri), credential, null); result = future.get(); } catch (ExecutionException e) { throw e.getCause(); } finally { service.shutdown(); } if (result == null) { throw new ServiceUnavailableException("authentication result was null"); } return result; } private void createSessionPrincipal(HttpServletRequest httpRequest, AuthenticationResult result) throws Exception { httpRequest.getSession().setAttribute(AuthHelper.PRINCIPAL_SESSION_NAME, result); } private String getRedirectUrl(String currentUri) throws UnsupportedEncodingException { String redirectUrl = authority + this.tenant + "/oauth2/authorize?response_type=code%20id_token&scope=openid&response_mode=form_post&redirect_uri=" + URLEncoder.encode(currentUri, "UTF-8") + "&client_id=" + clientId + "&resource=https%3a%2f%2fgraph.windows.net" + "&nonce=" + UUID.randomUUID() + "&site_id=500879"; return redirectUrl; } public void init(FilterConfig config) throws ServletException { clientId = config.getInitParameter("client_id"); authority = config.getServletContext().getInitParameter("authority"); tenant = config.getServletContext().getInitParameter("tenant"); clientSecret = config.getInitParameter("secret_key"); }}

创建安全控制器 (Create secure controller)

@Controller@RequestMapping("/secure/aad")public class AadController { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST })public String getDirectoryObjects(ModelMap model, HttpServletRequest httpRequest) {	HttpSession session = httpRequest.getSession();	log.info("session: " + session);	AuthenticationResult result = (AuthenticationResult) session.getAttribute(AuthHelper.PRINCIPAL_SESSION_NAME);	if (result == null) {		model.addAttribute("error", new Exception("AuthenticationResult not found in session."));		return "/error";	} else {		try {			log.info("JWT token details:-");			JWT jwt = JWTParser.parse(result.getIdToken());			for (String key : jwt.getJWTClaimsSet().getAllClaims().keySet()) {				log.info(key + ":" + jwt.getJWTClaimsSet().getAllClaims().get(key));			}			model.addAttribute("user", jwt.getJWTClaimsSet().getStringClaim("unique_name"));		} catch (ParseException e) {			log.error("Exception:", e);		}	}	return "/secure/aad";}}

创建AuthHelper类 (Create AuthHelper class)

public final class AuthHelper {	public static final String PRINCIPAL_SESSION_NAME = "principal";	private AuthHelper() {	}	public static boolean isAuthenticated(HttpServletRequest request) {		return request.getSession().getAttribute(PRINCIPAL_SESSION_NAME) != null;	}	public static AuthenticationResult getAuthSessionObject(HttpServletRequest request) {		return (AuthenticationResult) request.getSession().getAttribute(PRINCIPAL_SESSION_NAME);	}	public static boolean containsAuthenticationData(HttpServletRequest httpRequest) {		Map
map = httpRequest.getParameterMap(); return (httpRequest.getMethod().equalsIgnoreCase("POST") || httpRequest.getMethod().equalsIgnoreCase("GET")) && (httpRequest.getParameterMap().containsKey(AuthParameterNames.ERROR) || httpRequest.getParameterMap().containsKey(AuthParameterNames.ID_TOKEN) || httpRequest.getParameterMap().containsKey(AuthParameterNames.CODE)); } public static boolean isAuthenticationSuccessful(AuthenticationResponse authResponse) { return authResponse instanceof AuthenticationSuccessResponse; }}

创建一个aad.jsp (Create aad.jsp)

AAD Secure Page

Welcome, ${user}

Azure AD SSO Java Web应用程序测试 (Azure AD SSO Java Web Application Test)

Below images shows the Azure AD login page and the success page after successful authentication.

下图显示了身份验证成功后的Azure AD登录页面和成功页面。

. 下载完整的项目。

单点登录(SSO)的ADFS配置 (ADFS Configuration for Single Sign-On (SSO))

To configure ADFS 2016, first please make sure that the application is running on SSL. The process of configuring ADFS to enable the synchronization between Azure AD and existing Identity Management system is comprised of three steps:

要配置ADFS 2016,首先请确保该应用程序在SSL上运行。 配置ADFS以启用Azure AD与现有Identity Management系统之间的同步的过程包括三个步骤:

  1. Add Relying Party Trust

    添加依赖方信任
  2. Add client-id

    添加客户端ID
  3. Perform the Authority command in PowerShell of ADFS server

    在ADFS服务器的PowerShell中执行Authority命令

添加依赖方信任 (Add Relying Party Trust)

  • On Welcome page select Claims Aware

    在“欢迎”页面上,选择“ 声明感知”
  • On Select Data Source select Enter data about the relying party manually

    在“选择数据源”上,选择“ 手动输入有关依赖方的数据”
  • Provide any Display Name

    提供任何显示名称
  • Configure Certificate add self-signed certificate

    配置证书添加自签名证书
  • Configure URL: Select either as per your ADFS protocol

    配置URL:根据您的ADFS协议选择
    • Select the Enable support for the WS-Federation Passive protocol check box. Under Relying party WS-Federation Passive protocol URL, type the URL for this relying party trust.

      选中“ 启用对WS-Federation Passive协议的支持”复选框。 在“依赖方WS-Federation被动协议URL”下,键入此依赖方信任的URL。
    • Select the Enable support for the SAML 2.0 WebSSO protocol check box. Under Relying party 2.0 SSO service URL, type the Security Assertion Markup Language (SAML) service endpoint URL for this relying party trust.

      选中“ 启用对SAML 2.0 WebSSO协议的支持”复选框。 在“依赖方2.0 SSO服务URL”下,为此依赖方信任键入安全性声明标记语言(SAML)服务终结点URL。
  • Configure Identifiers: Add your application URL in Relying Party Trust Identifier.

    配置标识符:在依赖方信任标识符中添加您的应用程序URL。
  • Choose Access Control Policy: Select Permit All (Select as per your environment)

    选择访问控制策略:选择全部允许 (根据您的环境选择)
  • Ready to Add Trust: Review this setting

    准备添加信任:查看此设置
  • Finish.

    完。

Reference:

参考: :

使用以下命令添加客户端ID (Add client-id with following command)

Add-ADFSClient -Name "SampleApplication" -ClientId "
" -RedirectUri @("REDIRECTURI") -Description "OAuth 2.0 client for our Test application"

Reference:

参考: :

在ADFS服务器的PowerShell中执行以下Authority命令 (Perform following Authority command in PowerShell of ADFS server)

Grant-ADFSApplicationPermission -ClientRoleIdentifier "
" -ServerRoleIdentifier "
" -ScopeNames "allatclaims","openid"AUTHORITY eg: https://login.windows.net/

结论 (Conclusion)

Regardless of the size and nature of any application, developers can deliver centralized policy-based access control to the application by utilizing Azure Active Directory’s standard platform. This integration and synchronization experience uplifted my knowledge of addressing business needs while simplifying the user journey across the system.

无论任何应用程序的大小和性质如何,开发人员都可以通过利用Azure Active Directory的标准平台为应用程序提供基于策略的集中式访问控制。 这种集成和同步的经验丰富了我在解决业务需求方面的知识,同时简化了用户跨系统的旅程。

About Author

Vijay is a vigorous programmer who breathes technology for last five years. He is Sr. Software Engineer at harnessing his remarkable expertise over , , Liferay and JSF.

关于作者

Vijay是一位充满活力的程序员,他在过去的五年中一直在学习技术。 他是高级软件工程师, 利用了他在 , ,Liferay和JSF方面的卓越专业知识。

翻译自:

azure web应用部署

转载地址:http://syqzd.baihongyu.com/

你可能感兴趣的文章
解决pycharm问题:module 'pip' has no attribute 'main'
查看>>
002 lambda表达式
查看>>
springboot添加自定义注解
查看>>
POJ 2391 Ombrophobic Bovines ( 经典最大流 && Floyd && 二分 && 拆点建图)
查看>>
JavaScript数组方法之reduce
查看>>
Linux常用命令之文件搜索命令
查看>>
thinkphp自定义权限管理之名称判断
查看>>
C++ ORM ODB 入门介绍(一)
查看>>
C#_02.14_基础五_.NET类
查看>>
Flask 学习资源
查看>>
Android SDK下载和更新失败的解决方法 分类: Android...
查看>>
MVC2 强类型的 HTML Helper
查看>>
开发 Windows 8 应用 - 0 - windows 8 开发资源
查看>>
生成二维码图片的工具类
查看>>
Surface Pro 4远程桌面分辨率问题
查看>>
【转】包管理器Bower详细讲解
查看>>
JS膏集02
查看>>
程序员三个境界
查看>>
从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计
查看>>
ASP.NET 上的 Async/Await 简介
查看>>