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 com.nimbusds.common.contenttype.ContentType; 022import com.nimbusds.oauth2.sdk.ParseException; 023import com.nimbusds.oauth2.sdk.SerializeException; 024import com.nimbusds.oauth2.sdk.http.HTTPRequest; 025import com.nimbusds.oauth2.sdk.id.ClientID; 026import com.nimbusds.oauth2.sdk.util.URLUtils; 027 028import javax.net.ssl.SSLSocketFactory; 029import java.security.cert.X509Certificate; 030import java.util.*; 031 032 033/** 034 * The base abstract class for mutual TLS client authentication at the Token 035 * endpoint. 036 */ 037public abstract class TLSClientAuthentication extends ClientAuthentication { 038 039 040 /** 041 * The validated client X.509 certificate from the received HTTPS 042 * request, {@code null} for an outgoing HTTPS request. 043 */ 044 protected final X509Certificate certificate; 045 046 047 /** 048 * The SSL socket factory for an outgoing HTTPS request, {@code null} 049 * to use the default one. 050 */ 051 private final SSLSocketFactory sslSocketFactory; 052 053 054 /** 055 * Creates a new abstract mutual TLS client authentication. This 056 * constructor is intended for an outgoing token request. 057 * 058 * @param method The client authentication method. Must not 059 * be {@code null}. 060 * @param clientID The client identifier. Must not be 061 * {@code null}. 062 * @param sslSocketFactory The SSL socket factory to use for the 063 * outgoing HTTPS request and to present the 064 * client certificate(s), {@code null} to use 065 * the default one. 066 */ 067 protected TLSClientAuthentication(final ClientAuthenticationMethod method, 068 final ClientID clientID, 069 final SSLSocketFactory sslSocketFactory) { 070 071 super(method, clientID); 072 this.sslSocketFactory = sslSocketFactory; 073 certificate = null; 074 } 075 076 077 /** 078 * Creates a new abstract mutual TLS client authentication. This 079 * constructor is intended for a received token request. 080 * 081 * @param method The client authentication method. Must not be 082 * {@code null}. 083 * @param clientID The client identifier. Must not be {@code null}. 084 * @param certificate The validated client X.509 certificate from the 085 * received HTTPS request. Should not be 086 * {@code null}. 087 */ 088 protected TLSClientAuthentication(final ClientAuthenticationMethod method, 089 final ClientID clientID, 090 final X509Certificate certificate) { 091 super(method, clientID); 092 sslSocketFactory = null; 093 this.certificate = certificate; 094 } 095 096 097 /** 098 * Returns the SSL socket factory to use for an outgoing HTTPS request 099 * and to present the client certificate(s). 100 * 101 * @return The SSL socket factory, {@code null} to use the default one. 102 */ 103 public SSLSocketFactory getSSLSocketFactory() { 104 105 return sslSocketFactory; 106 } 107 108 109 /** 110 * The validated client X.509 certificate from the received HTTPS 111 * request. 112 * 113 * @return The validated client X.509 certificate from the received 114 * HTTPS request, {@code null} for an outgoing HTTPS request. 115 */ 116 public X509Certificate getClientX509Certificate() { 117 118 return certificate; 119 } 120 121 122 @Override 123 public Set<String> getFormParameterNames() { 124 125 return Collections.singleton("client_id"); 126 } 127 128 129 @Override 130 public void applyTo(final HTTPRequest httpRequest) { 131 132 if (httpRequest.getMethod() != HTTPRequest.Method.POST) 133 throw new SerializeException("The HTTP request method must be POST"); 134 135 ContentType ct = httpRequest.getEntityContentType(); 136 137 if (ct == null) 138 throw new SerializeException("Missing HTTP Content-Type header"); 139 140 if (ct.matches(ContentType.APPLICATION_JSON)) { 141 142 // Possibly request object POST request, nothing to set 143 144 } else if (ct.matches(ContentType.APPLICATION_URLENCODED)) { 145 146 // Token or similar request 147 Map<String, List<String>> params; 148 try { 149 params = new LinkedHashMap<>(httpRequest.getBodyAsFormParameters()); 150 } catch (ParseException e) { 151 throw new SerializeException(e.getMessage(), e); 152 } 153 params.put("client_id", Collections.singletonList(getClientID().getValue())); 154 httpRequest.setBody(URLUtils.serializeParameters(params)); 155 156 } else { 157 throw new SerializeException("The HTTP Content-Type header must be " + ContentType.APPLICATION_URLENCODED); 158 } 159 160 // If set for an outgoing request 161 httpRequest.setSSLSocketFactory(sslSocketFactory); 162 } 163}