App Engine Python SDK version 1.7.4 (2)
[gae.git] / java / src / main / com / google / appengine / api / appidentity / AppIdentityServiceImpl.java
blob4017f0a59f696739570cd57cc12283f80fc2d8d2
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 package com.google.appengine.api.appidentity;
4 import com.google.appengine.api.appidentity.AppIdentityServicePb.AppIdentityServiceError;
5 import com.google.appengine.api.appidentity.AppIdentityServicePb.GetAccessTokenRequest;
6 import com.google.appengine.api.appidentity.AppIdentityServicePb.GetAccessTokenResponse;
7 import com.google.appengine.api.appidentity.AppIdentityServicePb.GetPublicCertificateForAppRequest;
8 import com.google.appengine.api.appidentity.AppIdentityServicePb.GetPublicCertificateForAppResponse;
9 import com.google.appengine.api.appidentity.AppIdentityServicePb.GetServiceAccountNameRequest;
10 import com.google.appengine.api.appidentity.AppIdentityServicePb.GetServiceAccountNameResponse;
11 import com.google.appengine.api.appidentity.AppIdentityServicePb.SignForAppRequest;
12 import com.google.appengine.api.appidentity.AppIdentityServicePb.SignForAppResponse;
13 import com.google.appengine.api.memcache.Expiration;
14 import com.google.appengine.api.memcache.MemcacheService;
15 import com.google.appengine.api.memcache.MemcacheServiceFactory;
16 import com.google.apphosting.api.ApiProxy;
17 import com.google.common.collect.Lists;
18 import com.google.protobuf.ByteString;
19 import com.google.protobuf.InvalidProtocolBufferException;
21 import java.util.Date;
22 import java.util.List;
24 /**
25 * Implementation of the AppIdentityService interface.
28 class AppIdentityServiceImpl implements AppIdentityService {
30 public static final String PACKAGE_NAME = "app_identity_service";
32 public static final String SIGN_FOR_APP_METHOD_NAME = "SignForApp";
34 public static final String GET_SERVICE_ACCOUNT_NAME_METHOD_NAME = "GetServiceAccountName";
36 public static final String GET_CERTS_METHOD_NAME = "GetPublicCertificatesForApp";
38 public static final String GET_ACCESS_TOKEN_METHOD_NAME = "GetAccessToken";
40 public static final String MEMCACHE_NAMESPACE = "_ah_";
42 public static final String MEMCACHE_KEY_PREFIX = "_ah_app_identity_";
44 private static final char APP_PARTITION_SEPARATOR = '~';
45 private static final char APP_DOMAIN_SEPARATOR = ':';
47 private void handleApplicationError(ApiProxy.ApplicationException e) {
48 switch (AppIdentityServiceError.ErrorCode.valueOf(e.getApplicationError())) {
49 case BLOB_TOO_LARGE:
50 throw new AppIdentityServiceFailureException(e.getErrorDetail());
51 case NOT_A_VALID_APP:
52 throw new AppIdentityServiceFailureException(e.getErrorDetail());
53 case DEADLINE_EXCEEDED:
54 throw new AppIdentityServiceFailureException(e.getErrorDetail());
55 case UNKNOWN_ERROR:
56 throw new AppIdentityServiceFailureException(e.getErrorDetail());
57 case UNKNOWN_SCOPE:
58 throw new AppIdentityServiceFailureException(e.getErrorDetail());
59 default:
60 throw new AppIdentityServiceFailureException(e.getErrorDetail());
64 @Override
65 public List<PublicCertificate> getPublicCertificatesForApp() {
66 GetPublicCertificateForAppRequest.Builder requestBuilder =
67 GetPublicCertificateForAppRequest.newBuilder();
68 GetPublicCertificateForAppResponse.Builder responseBuilder =
69 GetPublicCertificateForAppResponse.newBuilder();
71 try {
72 responseBuilder.mergeFrom(
73 ApiProxy.makeSyncCall(
74 PACKAGE_NAME, GET_CERTS_METHOD_NAME, requestBuilder.build().toByteArray()));
75 } catch (ApiProxy.ApplicationException e) {
76 handleApplicationError(e);
77 } catch (InvalidProtocolBufferException e) {
78 throw new AppIdentityServiceFailureException(e.getMessage());
80 GetPublicCertificateForAppResponse response = responseBuilder.build();
82 List<PublicCertificate> certs = Lists.newArrayList();
83 for (AppIdentityServicePb.PublicCertificate cert : response.getPublicCertificateListList()) {
84 certs.add(new PublicCertificate(cert.getKeyName(), cert.getX509CertificatePem()));
86 return certs;
89 @Override
90 public SigningResult signForApp(byte[] signBlob) {
91 SignForAppRequest.Builder requestBuilder = SignForAppRequest.newBuilder();
92 requestBuilder.setBytesToSign(ByteString.copyFrom(signBlob));
93 SignForAppResponse.Builder responseBuilder = SignForAppResponse.newBuilder();
94 try {
95 responseBuilder.mergeFrom(
96 ApiProxy.makeSyncCall(
97 PACKAGE_NAME, SIGN_FOR_APP_METHOD_NAME, requestBuilder.build().toByteArray()));
98 } catch (ApiProxy.ApplicationException e) {
99 handleApplicationError(e);
100 } catch (InvalidProtocolBufferException e) {
101 throw new AppIdentityServiceFailureException(e.getMessage());
104 SignForAppResponse response = responseBuilder.build();
105 return new SigningResult(response.getKeyName(), response.getSignatureBytes().toByteArray());
108 @Override
109 public String getServiceAccountName() {
110 GetServiceAccountNameRequest.Builder requestBuilder = GetServiceAccountNameRequest.newBuilder();
111 GetServiceAccountNameResponse.Builder responseBuilder =
112 GetServiceAccountNameResponse.newBuilder();
113 try {
114 responseBuilder.mergeFrom(
115 ApiProxy.makeSyncCall(
116 PACKAGE_NAME, GET_SERVICE_ACCOUNT_NAME_METHOD_NAME,
117 requestBuilder.build().toByteArray()));
118 } catch (ApiProxy.ApplicationException e) {
119 handleApplicationError(e);
120 } catch (InvalidProtocolBufferException e) {
121 throw new AppIdentityServiceFailureException(e.getMessage());
124 GetServiceAccountNameResponse response = responseBuilder.build();
125 return response.getServiceAccountName();
128 @Override
129 public GetAccessTokenResult getAccessTokenUncached(Iterable<String> scopes) {
130 GetAccessTokenRequest.Builder requestBuilder = GetAccessTokenRequest.newBuilder();
131 for (String scope : scopes) {
132 requestBuilder.addScope(scope);
134 if (requestBuilder.getScopeCount() == 0) {
135 throw new AppIdentityServiceFailureException("No scopes specified.");
137 GetAccessTokenResponse.Builder responseBuilder = GetAccessTokenResponse.newBuilder();
138 try {
139 responseBuilder.mergeFrom(
140 ApiProxy.makeSyncCall(
141 PACKAGE_NAME, GET_ACCESS_TOKEN_METHOD_NAME,
142 requestBuilder.build().toByteArray()));
143 } catch (ApiProxy.ApplicationException e) {
144 handleApplicationError(e);
145 } catch (InvalidProtocolBufferException e) {
146 throw new AppIdentityServiceFailureException(e.getMessage());
149 GetAccessTokenResponse response = responseBuilder.build();
150 return new GetAccessTokenResult(response.getAccessToken(),
151 new Date(response.getExpirationTime() * 1000));
154 private String memcacheKeyForScopes(Iterable<String> scopes) {
155 StringBuilder builder = new StringBuilder();
156 builder.append(MEMCACHE_KEY_PREFIX);
157 builder.append("[");
158 boolean first = true;
159 for (String scope : scopes) {
160 if (first) {
161 first = false;
162 } else {
163 builder.append(",");
165 builder.append("'");
166 builder.append(scope);
167 builder.append("'");
169 builder.append("]");
170 return builder.toString();
173 @Override
174 public GetAccessTokenResult getAccessToken(Iterable<String> scopes) {
175 MemcacheService memcache = MemcacheServiceFactory.getMemcacheService(MEMCACHE_NAMESPACE);
176 String memcacheKey = memcacheKeyForScopes(scopes);
177 GetAccessTokenResult result;
178 Object memcacheResult = memcache.get(memcacheKey);
179 if (memcacheResult != null) {
180 result = (GetAccessTokenResult) memcacheResult;
181 } else {
182 result = getAccessTokenUncached(scopes);
183 Date memcacheExpiration = new Date(result.getExpirationTime().getTime() - 300000);
184 memcache.put(memcacheKey, result, Expiration.onDate(memcacheExpiration));
186 return result;
189 @Override
190 public ParsedAppId parseFullAppId(String fullAppId) {
191 int partitionIdx = fullAppId.indexOf(APP_PARTITION_SEPARATOR);
192 String partition;
193 if (partitionIdx > 0) {
194 partition = fullAppId.substring(0, partitionIdx);
195 fullAppId = fullAppId.substring(partitionIdx + 1);
196 } else {
197 partition = "";
200 int domainIdx = fullAppId.indexOf(APP_DOMAIN_SEPARATOR);
201 String domain;
202 if (domainIdx > 0) {
203 domain = fullAppId.substring(0, domainIdx);
204 fullAppId = fullAppId.substring(domainIdx + 1);
205 } else {
206 domain = "";
209 return new ParsedAppId(partition, domain, fullAppId);