]> source.dussan.org Git - archiva.git/blob
6fd85d5cf47fe42662d956eed0f18e24e772d085
[archiva.git] /
1 package org.apache.archiva.rest.services.v2;
2 /*
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19
20 import org.apache.archiva.admin.model.AuditInformation;
21 import org.apache.archiva.admin.model.RepositoryAdminException;
22 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
23 import org.apache.archiva.components.rest.model.PagedResult;
24 import org.apache.archiva.components.rest.util.QueryHelper;
25 import org.apache.archiva.redback.authentication.AuthenticationResult;
26 import org.apache.archiva.redback.authorization.AuthorizationException;
27 import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal;
28 import org.apache.archiva.redback.rest.services.RedbackRequestInformation;
29 import org.apache.archiva.redback.system.DefaultSecuritySession;
30 import org.apache.archiva.redback.system.SecuritySession;
31 import org.apache.archiva.redback.system.SecuritySystem;
32 import org.apache.archiva.redback.users.User;
33 import org.apache.archiva.redback.users.UserManagerException;
34 import org.apache.archiva.redback.users.UserNotFoundException;
35 import org.apache.archiva.repository.ManagedRepository;
36 import org.apache.archiva.repository.ReleaseScheme;
37 import org.apache.archiva.repository.Repository;
38 import org.apache.archiva.repository.RepositoryException;
39 import org.apache.archiva.repository.RepositoryRegistry;
40 import org.apache.archiva.repository.RepositoryType;
41 import org.apache.archiva.repository.content.ContentItem;
42 import org.apache.archiva.repository.content.LayoutException;
43 import org.apache.archiva.repository.storage.fs.FilesystemStorage;
44 import org.apache.archiva.repository.storage.fs.FsStorageUtil;
45 import org.apache.archiva.repository.storage.util.StorageUtil;
46 import org.apache.archiva.rest.api.model.v2.Artifact;
47 import org.apache.archiva.rest.api.model.v2.FileInfo;
48 import org.apache.archiva.rest.api.model.v2.MavenManagedRepository;
49 import org.apache.archiva.rest.api.model.v2.MavenManagedRepositoryUpdate;
50 import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException;
51 import org.apache.archiva.rest.api.services.v2.ErrorKeys;
52 import org.apache.archiva.rest.api.services.v2.ErrorMessage;
53 import org.apache.archiva.rest.api.services.v2.MavenManagedRepositoryService;
54 import org.apache.archiva.security.common.ArchivaRoleConstants;
55 import org.apache.commons.lang3.StringUtils;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58 import org.springframework.stereotype.Service;
59
60 import javax.inject.Inject;
61 import javax.servlet.http.HttpServletResponse;
62 import javax.ws.rs.PathParam;
63 import javax.ws.rs.core.Context;
64 import javax.ws.rs.core.Response;
65 import javax.ws.rs.core.UriInfo;
66 import java.io.File;
67 import java.io.IOException;
68 import java.util.Collection;
69 import java.util.Comparator;
70 import java.util.List;
71 import java.util.function.Predicate;
72 import java.util.stream.Collectors;
73
74 import static org.apache.archiva.security.common.ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS;
75 import static org.apache.archiva.security.common.ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD;
76
77 /**
78  * @author Martin Stockhammer <martin_s@apache.org>
79  */
80 @Service("v2.managedMavenRepositoryService#rest")
81 public class DefaultMavenManagedRepositoryService implements MavenManagedRepositoryService
82 {
83     @Context
84     HttpServletResponse httpServletResponse;
85
86     @Context
87     UriInfo uriInfo;
88
89     private static final Logger log = LoggerFactory.getLogger( DefaultMavenManagedRepositoryService.class );
90     private static final QueryHelper<ManagedRepository> QUERY_HELPER = new QueryHelper<>( new String[]{"id", "name"} );
91     static
92     {
93         QUERY_HELPER.addStringFilter( "id", ManagedRepository::getId );
94         QUERY_HELPER.addStringFilter( "name", ManagedRepository::getName );
95         QUERY_HELPER.addStringFilter( "location", (r)  -> r.getLocation().toString() );
96         QUERY_HELPER.addBooleanFilter( "snapshot", (r) -> r.getActiveReleaseSchemes( ).contains( ReleaseScheme.SNAPSHOT ) );
97         QUERY_HELPER.addBooleanFilter( "release", (r) -> r.getActiveReleaseSchemes().contains( ReleaseScheme.RELEASE ));
98         QUERY_HELPER.addNullsafeFieldComparator( "id", ManagedRepository::getId );
99         QUERY_HELPER.addNullsafeFieldComparator( "name", ManagedRepository::getName );
100     }
101
102     private ManagedRepositoryAdmin managedRepositoryAdmin;
103     private RepositoryRegistry repositoryRegistry;
104     private SecuritySystem securitySystem;
105
106     public DefaultMavenManagedRepositoryService( SecuritySystem securitySystem, RepositoryRegistry repositoryRegistry, ManagedRepositoryAdmin managedRepositoryAdmin )
107     {
108         this.securitySystem = securitySystem;
109         this.repositoryRegistry = repositoryRegistry;
110         this.managedRepositoryAdmin = managedRepositoryAdmin;
111     }
112
113     protected AuditInformation getAuditInformation( )
114     {
115         RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get( );
116         User user = redbackRequestInformation == null ? null : redbackRequestInformation.getUser( );
117         String remoteAddr = redbackRequestInformation == null ? null : redbackRequestInformation.getRemoteAddr( );
118         return new AuditInformation( user, remoteAddr );
119     }
120
121     @Override
122     public PagedResult<MavenManagedRepository> getManagedRepositories( final String searchTerm, final Integer offset,
123                                                                        final Integer limit, final List<String> orderBy,
124                                                                        final String order ) throws ArchivaRestServiceException
125     {
126         try
127         {
128             Collection<ManagedRepository> repos = repositoryRegistry.getManagedRepositories( );
129             final Predicate<ManagedRepository> queryFilter = QUERY_HELPER.getQueryFilter( searchTerm ).and( r -> r.getType() == RepositoryType.MAVEN );
130             final Comparator<ManagedRepository> comparator = QUERY_HELPER.getComparator( orderBy, order );
131             int totalCount = Math.toIntExact( repos.stream( ).filter( queryFilter ).count( ) );
132             return PagedResult.of( totalCount, offset, limit, repos.stream( ).filter( queryFilter ).sorted( comparator )
133                 .map(mr -> MavenManagedRepository.of(mr)).skip( offset ).limit( limit ).collect( Collectors.toList( ) ) );
134         }
135         catch (ArithmeticException e) {
136             log.error( "Invalid number of repositories detected." );
137             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.INVALID_RESULT_SET_ERROR ) );
138         }
139     }
140
141     @Override
142     public MavenManagedRepository getManagedRepository( String repositoryId ) throws ArchivaRestServiceException
143     {
144         ManagedRepository repo = repositoryRegistry.getManagedRepository( repositoryId );
145         if (repo==null) {
146             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, repositoryId ), 404 );
147         }
148         if (repo.getType()!=RepositoryType.MAVEN) {
149             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_WRONG_TYPE, repositoryId, repo.getType().name() ), 404 );
150         }
151         return MavenManagedRepository.of( repo );
152     }
153
154     @Override
155     public Response deleteManagedRepository( String repositoryId, boolean deleteContent ) throws ArchivaRestServiceException
156     {
157         ManagedRepository repo = repositoryRegistry.getManagedRepository( repositoryId );
158         if (repo==null) {
159             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, repositoryId ), 404 );
160         }
161         if (repo.getType()!=RepositoryType.MAVEN) {
162             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_WRONG_TYPE, repositoryId, repo.getType().name() ), 404 );
163         }
164         try
165         {
166             managedRepositoryAdmin.deleteManagedRepository( repositoryId, getAuditInformation( ), deleteContent );
167             return Response.ok( ).build( );
168         }
169         catch ( RepositoryAdminException e )
170         {
171             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_DELETE_FAILED, e.getMessage( ) ) );
172         }
173     }
174
175     private org.apache.archiva.admin.model.beans.ManagedRepository convert(MavenManagedRepository repository) {
176         org.apache.archiva.admin.model.beans.ManagedRepository repoBean = new org.apache.archiva.admin.model.beans.ManagedRepository( );
177         repoBean.setId( repository.getId( ) );
178         repoBean.setName( repository.getName() );
179         repoBean.setDescription( repository.getDescription() );
180         repoBean.setBlockRedeployments( repository.isBlocksRedeployments() );
181         repoBean.setCronExpression( repository.getSchedulingDefinition() );
182         repoBean.setLocation( repository.getLocation() );
183         repoBean.setReleases( repository.getReleaseSchemes().contains( ReleaseScheme.RELEASE.name() ) );
184         repoBean.setSnapshots( repository.getReleaseSchemes().contains( ReleaseScheme.SNAPSHOT.name() ) );
185         repoBean.setScanned( repository.isScanned() );
186         repoBean.setDeleteReleasedSnapshots( repository.isDeleteSnapshotsOfRelease() );
187         repoBean.setSkipPackedIndexCreation( repository.isSkipPackedIndexCreation() );
188         repoBean.setRetentionCount( repository.getRetentionCount() );
189         repoBean.setRetentionPeriod( repository.getRetentionPeriod().getDays() );
190         repoBean.setIndexDirectory( repository.getIndexPath() );
191         repoBean.setPackedIndexDirectory( repository.getPackedIndexPath() );
192         repoBean.setLayout( repository.getLayout() );
193         repoBean.setType( RepositoryType.MAVEN.name( ) );
194         return repoBean;
195     }
196
197     @Override
198     public MavenManagedRepository addManagedRepository( MavenManagedRepository managedRepository ) throws ArchivaRestServiceException
199     {
200         final String repoId = managedRepository.getId( );
201         if ( StringUtils.isEmpty( repoId ) ) {
202             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_INVALID_ID, repoId ), 422 );
203         }
204         Repository repo = repositoryRegistry.getRepository( repoId );
205         if (repo!=null) {
206             httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder( ).path( repoId ).build( ).toString( ) );
207             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ID_EXISTS, repoId ), 303 );
208         }
209         try
210         {
211             managedRepositoryAdmin.addManagedRepository( convert( managedRepository ), managedRepository.isHasStagingRepository(), getAuditInformation() );
212             httpServletResponse.setStatus( 201 );
213             return MavenManagedRepository.of( repositoryRegistry.getManagedRepository( repoId ) );
214         }
215         catch ( RepositoryAdminException e )
216         {
217             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
218         }
219     }
220
221     @Override
222     public MavenManagedRepository updateManagedRepository( final String repositoryId, final MavenManagedRepositoryUpdate managedRepository ) throws ArchivaRestServiceException
223     {
224         org.apache.archiva.admin.model.beans.ManagedRepository repo = convert( managedRepository );
225         try
226         {
227             managedRepositoryAdmin.updateManagedRepository( repo, managedRepository.isHasStagingRepository( ), getAuditInformation( ), managedRepository.isResetStats( ) );
228             ManagedRepository newRepo = repositoryRegistry.getManagedRepository( managedRepository.getId( ) );
229             if (newRepo==null) {
230                 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_UPDATE_FAILED, repositoryId ) );
231             }
232             return MavenManagedRepository.of( newRepo );
233         }
234         catch ( RepositoryAdminException e )
235         {
236             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
237         }
238     }
239
240     @Override
241     public FileInfo getFileStatus( String repositoryId, String fileLocation ) throws ArchivaRestServiceException
242     {
243         ManagedRepository repo = repositoryRegistry.getManagedRepository( repositoryId );
244         if (repo==null) {
245             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, repositoryId ), 404 );
246         }
247         try
248         {
249             ContentItem contentItem = repo.getContent( ).toItem( fileLocation );
250             if (contentItem.getAsset( ).exists( ))  {
251                 return FileInfo.of( contentItem.getAsset( ) );
252             } else {
253                 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.ARTIFACT_NOT_FOUND, repositoryId, fileLocation ), 404 );
254             }
255         }
256         catch ( LayoutException e )
257         {
258             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_LAYOUT_ERROR, e.getMessage( ) ) );
259         }
260     }
261
262     @Override
263     public Response copyArtifact( String srcRepositoryId, String dstRepositoryId,
264                                   String path ) throws ArchivaRestServiceException
265     {
266         final AuditInformation auditInformation = getAuditInformation( );
267         final String userName = auditInformation.getUser( ).getUsername( );
268         if ( StringUtils.isEmpty( userName ) )
269         {
270             httpServletResponse.setHeader( "WWW-Authenticate", "Bearer realm=\"archiva\"" );
271             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.NOT_AUTHENTICATED ), 401 );
272         }
273         ManagedRepository srcRepo = repositoryRegistry.getManagedRepository( srcRepositoryId );
274         if (srcRepo==null) {
275             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, srcRepositoryId ), 404 );
276         }
277         ManagedRepository dstRepo = repositoryRegistry.getManagedRepository( dstRepositoryId );
278         if (dstRepo==null) {
279             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_NOT_FOUND, dstRepositoryId ), 404 );
280         }
281         checkAuthority( auditInformation.getUser().getUsername(), srcRepositoryId, dstRepositoryId );
282         try
283         {
284             ContentItem srcItem = srcRepo.getContent( ).toItem( path );
285             ContentItem dstItem = dstRepo.getContent( ).toItem( path );
286             if (!srcItem.getAsset().exists()){
287                 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.ARTIFACT_NOT_FOUND, srcRepositoryId, path ), 404 );
288             }
289             if (dstItem.getAsset().exists()) {
290                 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.ARTIFACT_EXISTS_AT_DEST, srcRepositoryId, path ), 400 );
291             }
292             FsStorageUtil.copyAsset( srcItem.getAsset( ), dstItem.getAsset( ), true );
293         }
294         catch ( LayoutException e )
295         {
296             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_LAYOUT_ERROR, e.getMessage() ) );
297         }
298         catch ( IOException e )
299         {
300             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.ARTIFACT_COPY_ERROR, e.getMessage() ) );
301         }
302         return Response.ok( ).build();
303     }
304
305     private void checkAuthority(final String userName, final String srcRepositoryId, final String dstRepositoryId ) throws ArchivaRestServiceException {
306         User user = null;
307         try
308         {
309             user = securitySystem.getUserManager().findUser( userName );
310         }
311         catch ( UserNotFoundException e )
312         {
313             httpServletResponse.setHeader( "WWW-Authenticate", "Bearer realm=\"archiva\"" );
314             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.USER_NOT_FOUND, userName ), 401 );
315         }
316         catch ( UserManagerException e )
317         {
318             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.USER_MANAGER_ERROR, e.getMessage( ) ) );
319         }
320
321         // check karma on source : read
322         AuthenticationResult authn = new AuthenticationResult( true, userName, null );
323         SecuritySession securitySession = new DefaultSecuritySession( authn, user );
324         try
325         {
326             boolean authz =
327                 securitySystem.isAuthorized( securitySession, OPERATION_REPOSITORY_ACCESS,
328                     srcRepositoryId );
329             if ( !authz )
330             {
331                 throw new ArchivaRestServiceException(ErrorMessage.of( ErrorKeys.PERMISSION_REPOSITORY_DENIED, srcRepositoryId, OPERATION_REPOSITORY_ACCESS ), 403);
332             }
333         }
334         catch ( AuthorizationException e )
335         {
336             log.error( "Error reading permission: {}", e.getMessage(), e );
337             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.AUTHORIZATION_ERROR, e.getMessage() ), 403);
338         }
339
340         // check karma on target: write
341         try
342         {
343             boolean authz =
344                 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
345                     dstRepositoryId );
346             if ( !authz )
347             {
348                 throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PERMISSION_REPOSITORY_DENIED, dstRepositoryId, OPERATION_REPOSITORY_UPLOAD ) );
349             }
350         }
351         catch ( AuthorizationException e )
352         {
353             log.error( "Error reading permission: {}", e.getMessage(), e );
354             throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.AUTHORIZATION_ERROR, e.getMessage() ), 403);
355         }
356
357
358     }
359
360     @Override
361     public Response deleteArtifact( String repositoryId, String path ) throws ArchivaRestServiceException
362     {
363
364         return null;
365     }
366
367
368     @Override
369     public Response removeProjectVersion( String repositoryId, String namespace, String projectId, String version ) throws org.apache.archiva.rest.api.services.ArchivaRestServiceException
370     {
371         return null;
372     }
373
374     @Override
375     public Response deleteProject( String repositoryId, String namespace, String projectId ) throws org.apache.archiva.rest.api.services.ArchivaRestServiceException
376     {
377         return null;
378     }
379
380     @Override
381     public Response deleteNamespace( String repositoryId, String namespace ) throws org.apache.archiva.rest.api.services.ArchivaRestServiceException
382     {
383         return null;
384     }
385
386 }