001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk.auth; 019 020 021import java.util.List; 022import java.util.Map; 023import javax.net.ssl.SSLSocketFactory; 024 025import com.nimbusds.oauth2.sdk.ParseException; 026import com.nimbusds.oauth2.sdk.http.HTTPRequest; 027import com.nimbusds.oauth2.sdk.id.ClientID; 028import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils; 029import com.nimbusds.oauth2.sdk.util.StringUtils; 030import com.nimbusds.oauth2.sdk.util.URLUtils; 031import net.jcip.annotations.Immutable; 032 033 034/** 035 * PKI mutual TLS client authentication at the Token endpoint. The client 036 * certificate is PKI bound, as opposed to 037 * {@link SelfSignedTLSClientAuthentication self_signed_tls_client_auth} which 038 * relies on a self-signed certificate. Implements 039 * {@link ClientAuthenticationMethod#TLS_CLIENT_AUTH}. 040 * 041 * <p>Related specifications: 042 * 043 * <ul> 044 * <li>OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound 045 * Access Tokens (draft-ietf-oauth-mtls-14), section 2.1. 046 * </ul> 047 */ 048@Immutable 049public class PKITLSClientAuthentication extends TLSClientAuthentication { 050 051 052 /** 053 * The client X.509 certificate subject DN. 054 */ 055 private final String certSubjectDN; 056 057 058 /** 059 * Creates a new PKI mutual TLS client authentication. This constructor 060 * is intended for an outgoing token request. 061 * 062 * @param clientID The client identifier. Must not be 063 * {@code null}. 064 * @param sslSocketFactory The SSL socket factory to use for the 065 * outgoing HTTPS request and to present the 066 * client certificate(s), {@code null} to use 067 * the default one. 068 */ 069 public PKITLSClientAuthentication(final ClientID clientID, 070 final SSLSocketFactory sslSocketFactory) { 071 072 super(ClientAuthenticationMethod.TLS_CLIENT_AUTH, clientID, sslSocketFactory); 073 certSubjectDN = null; 074 } 075 076 077 /** 078 * Creates a new PKI mutual TLS client authentication. This constructor 079 * is intended for a received token request. 080 * 081 * @param clientID The client identifier. Must not be 082 * {@code null}. 083 * @param certSubjectDN The subject DN of the received validated client 084 * X.509 certificate. Must not be {@code null}. 085 */ 086 public PKITLSClientAuthentication(final ClientID clientID, 087 final String certSubjectDN) { 088 089 super(ClientAuthenticationMethod.TLS_CLIENT_AUTH, clientID); 090 091 if (certSubjectDN == null) { 092 throw new IllegalArgumentException("The X.509 client certificate subject DN must not be null"); 093 } 094 this.certSubjectDN = certSubjectDN; 095 } 096 097 098 /** 099 * Gets the subject DN of the received validated client X.509 100 * certificate. 101 * 102 * @return The subject DN. 103 */ 104 public String getClientX509CertificateSubjectDN() { 105 106 return certSubjectDN; 107 } 108 109 110 /** 111 * Parses a PKI mutual TLS client authentication from the specified 112 * HTTP request. 113 * 114 * @param httpRequest The HTTP request to parse. Must not be 115 * {@code null} and must include a validated client 116 * X.509 certificate. 117 * 118 * @return The PKI mutual TLS client authentication. 119 * 120 * @throws ParseException If the {@code client_id} or client X.509 121 * certificate is missing. 122 */ 123 public static PKITLSClientAuthentication parse(final HTTPRequest httpRequest) 124 throws ParseException { 125 126 String query = httpRequest.getQuery(); 127 128 if (query == null) { 129 throw new ParseException("Missing HTTP POST request entity body"); 130 } 131 132 Map<String,List<String>> params = URLUtils.parseParameters(query); 133 134 String clientIDString = MultivaluedMapUtils.getFirstValue(params, "client_id"); 135 136 if (StringUtils.isBlank(clientIDString)) { 137 throw new ParseException("Missing client_id parameter"); 138 } 139 140 if (httpRequest.getClientX509CertificateSubjectDN() == null) { 141 throw new ParseException("Missing client X.509 certificate subject DN"); 142 } 143 144 return new PKITLSClientAuthentication( 145 new ClientID(clientIDString), 146 httpRequest.getClientX509CertificateSubjectDN() 147 ); 148 } 149}