001/******************************************************************************* 002 * Copyright 2017 The MIT Internet Trust Consortium 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 *******************************************************************************/ 016package org.mitre.oauth2.service.impl; 017 018import static com.google.common.collect.Maps.newLinkedHashMap; 019 020import java.text.ParseException; 021import java.util.Map; 022import java.util.Set; 023 024import org.mitre.oauth2.model.OAuth2AccessTokenEntity; 025import org.mitre.oauth2.model.OAuth2RefreshTokenEntity; 026import org.mitre.oauth2.service.IntrospectionResultAssembler; 027import org.mitre.openid.connect.model.UserInfo; 028import org.mitre.uma.model.Permission; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031import org.springframework.security.oauth2.provider.OAuth2Authentication; 032import org.springframework.stereotype.Service; 033 034import com.google.common.base.Joiner; 035import com.google.common.collect.Sets; 036 037/** 038 * Default implementation of the {@link IntrospectionResultAssembler} interface. 039 */ 040@Service 041public class DefaultIntrospectionResultAssembler implements IntrospectionResultAssembler { 042 043 /** 044 * Logger for this class 045 */ 046 private static final Logger logger = LoggerFactory.getLogger(DefaultIntrospectionResultAssembler.class); 047 048 @Override 049 public Map<String, Object> assembleFrom(OAuth2AccessTokenEntity accessToken, UserInfo userInfo, Set<String> authScopes) { 050 051 Map<String, Object> result = newLinkedHashMap(); 052 OAuth2Authentication authentication = accessToken.getAuthenticationHolder().getAuthentication(); 053 054 result.put(ACTIVE, true); 055 056 if (accessToken.getPermissions() != null && !accessToken.getPermissions().isEmpty()) { 057 058 Set<Object> permissions = Sets.newHashSet(); 059 060 for (Permission perm : accessToken.getPermissions()) { 061 Map<String, Object> o = newLinkedHashMap(); 062 o.put("resource_set_id", perm.getResourceSet().getId().toString()); 063 Set<String> scopes = Sets.newHashSet(perm.getScopes()); 064 o.put("scopes", scopes); 065 permissions.add(o); 066 } 067 068 result.put("permissions", permissions); 069 070 } else { 071 Set<String> scopes = Sets.intersection(authScopes, accessToken.getScope()); 072 073 result.put(SCOPE, Joiner.on(SCOPE_SEPARATOR).join(scopes)); 074 075 } 076 077 if (accessToken.getExpiration() != null) { 078 try { 079 result.put(EXPIRES_AT, dateFormat.valueToString(accessToken.getExpiration())); 080 result.put(EXP, accessToken.getExpiration().getTime() / 1000L); 081 } catch (ParseException e) { 082 logger.error("Parse exception in token introspection", e); 083 } 084 } 085 086 if (userInfo != null) { 087 // if we have a UserInfo, use that for the subject 088 result.put(SUB, userInfo.getSub()); 089 } else { 090 // otherwise, use the authentication's username 091 result.put(SUB, authentication.getName()); 092 } 093 094 if(authentication.getUserAuthentication() != null) { 095 result.put(USER_ID, authentication.getUserAuthentication().getName()); 096 } 097 098 result.put(CLIENT_ID, authentication.getOAuth2Request().getClientId()); 099 100 result.put(TOKEN_TYPE, accessToken.getTokenType()); 101 102 return result; 103 } 104 105 @Override 106 public Map<String, Object> assembleFrom(OAuth2RefreshTokenEntity refreshToken, UserInfo userInfo, Set<String> authScopes) { 107 108 Map<String, Object> result = newLinkedHashMap(); 109 OAuth2Authentication authentication = refreshToken.getAuthenticationHolder().getAuthentication(); 110 111 result.put(ACTIVE, true); 112 113 Set<String> scopes = Sets.intersection(authScopes, authentication.getOAuth2Request().getScope()); 114 115 result.put(SCOPE, Joiner.on(SCOPE_SEPARATOR).join(scopes)); 116 117 if (refreshToken.getExpiration() != null) { 118 try { 119 result.put(EXPIRES_AT, dateFormat.valueToString(refreshToken.getExpiration())); 120 result.put(EXP, refreshToken.getExpiration().getTime() / 1000L); 121 } catch (ParseException e) { 122 logger.error("Parse exception in token introspection", e); 123 } 124 } 125 126 127 if (userInfo != null) { 128 // if we have a UserInfo, use that for the subject 129 result.put(SUB, userInfo.getSub()); 130 } else { 131 // otherwise, use the authentication's username 132 result.put(SUB, authentication.getName()); 133 } 134 135 if(authentication.getUserAuthentication() != null) { 136 result.put(USER_ID, authentication.getUserAuthentication().getName()); 137 } 138 139 result.put(CLIENT_ID, authentication.getOAuth2Request().getClientId()); 140 141 return result; 142 } 143}