001    package org.apache.archiva.web.startup;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *  http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.archiva.common.ArchivaException;
023    import org.apache.archiva.configuration.ArchivaConfiguration;
024    import org.apache.archiva.configuration.ConfigurationNames;
025    import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
026    import org.apache.archiva.redback.rbac.RBACManager;
027    import org.apache.archiva.redback.role.RoleManagerException;
028    import org.apache.archiva.redback.system.check.EnvironmentCheck;
029    import org.apache.archiva.security.common.ArchivaRoleConstants;
030    import org.apache.commons.collections.CollectionUtils;
031    import org.apache.commons.lang.StringUtils;
032    import org.apache.archiva.redback.rbac.RbacManagerException;
033    import org.apache.archiva.redback.rbac.UserAssignment;
034    import org.apache.archiva.redback.role.RoleManager;
035    import org.apache.archiva.redback.users.UserManager;
036    import org.apache.archiva.redback.components.registry.RegistryListener;
037    import org.apache.commons.lang.time.StopWatch;
038    import org.slf4j.Logger;
039    import org.slf4j.LoggerFactory;
040    import org.springframework.context.ApplicationContext;
041    import org.springframework.stereotype.Service;
042    
043    import javax.annotation.PostConstruct;
044    import javax.inject.Inject;
045    import javax.inject.Named;
046    import java.util.ArrayList;
047    import java.util.HashMap;
048    import java.util.List;
049    import java.util.Map;
050    import java.util.Map.Entry;
051    
052    /**
053     * ConfigurationSynchronization
054     */
055    @Service
056    public class SecuritySynchronization
057        implements RegistryListener
058    {
059        private Logger log = LoggerFactory.getLogger( SecuritySynchronization.class );
060    
061        @Inject
062        private RoleManager roleManager;
063    
064        @Inject
065        @Named(value = "rbacManager#cached")
066        private RBACManager rbacManager;
067    
068        private Map<String, EnvironmentCheck> checkers;
069    
070        @Inject
071        private ArchivaConfiguration archivaConfiguration;
072    
073        @Inject
074        private ApplicationContext applicationContext;
075    
076        @PostConstruct
077        public void initialize()
078        {
079            checkers = getBeansOfType( EnvironmentCheck.class );
080        }
081    
082        protected <T> Map<String, T> getBeansOfType( Class<T> clazz )
083        {
084            //TODO do some caching here !!!
085            // olamy : with plexus we get only roleHint
086            // as per convention we named spring bean role#hint remove role# if exists
087            Map<String, T> springBeans = applicationContext.getBeansOfType( clazz );
088    
089            Map<String, T> beans = new HashMap<String, T>( springBeans.size() );
090    
091            for ( Entry<String, T> entry : springBeans.entrySet() )
092            {
093                String key = StringUtils.substringAfterLast( entry.getKey(), "#" );
094                beans.put( key, entry.getValue() );
095            }
096            return beans;
097        }
098    
099        public void afterConfigurationChange( org.apache.archiva.redback.components.registry.Registry registry,
100                                              String propertyName, Object propertyValue )
101        {
102            if ( ConfigurationNames.isManagedRepositories( propertyName ) && propertyName.endsWith( ".id" ) )
103            {
104                if ( propertyValue != null )
105                {
106                    syncRepoConfiguration( (String) propertyValue );
107                }
108            }
109        }
110    
111        public void beforeConfigurationChange( org.apache.archiva.redback.components.registry.Registry registry,
112                                               String propertyName, Object propertyValue )
113        {
114            /* do nothing */
115        }
116    
117        private void synchConfiguration( List<ManagedRepositoryConfiguration> repos )
118        {
119            // NOTE: Remote Repositories do not have roles or security placed around them.
120    
121            for ( ManagedRepositoryConfiguration repoConfig : repos )
122            {
123                syncRepoConfiguration( repoConfig.getId() );
124            }
125        }
126    
127        private void syncRepoConfiguration( String id )
128        {
129            // manage roles for repositories
130            try
131            {
132                if ( !roleManager.templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, id ) )
133                {
134                    roleManager.createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, id );
135                }
136                else
137                {
138                    roleManager.verifyTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_OBSERVER, id );
139                }
140    
141                if ( !roleManager.templatedRoleExists( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, id ) )
142                {
143                    roleManager.createTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, id );
144                }
145                else
146                {
147                    roleManager.verifyTemplatedRole( ArchivaRoleConstants.TEMPLATE_REPOSITORY_MANAGER, id );
148                }
149            }
150            catch ( RoleManagerException e )
151            {
152                // Log error.
153                log.error( "Unable to create roles for configured repositories: " + e.getMessage(), e );
154            }
155        }
156    
157        public void startup()
158            throws ArchivaException
159        {
160            executeEnvironmentChecks();
161    
162            synchConfiguration( archivaConfiguration.getConfiguration().getManagedRepositories() );
163            archivaConfiguration.addChangeListener( this );
164    
165            if ( archivaConfiguration.isDefaulted() )
166            {
167                assignRepositoryObserverToGuestUser( archivaConfiguration.getConfiguration().getManagedRepositories() );
168            }
169        }
170    
171        private void executeEnvironmentChecks()
172            throws ArchivaException
173        {
174            if ( ( checkers == null ) || CollectionUtils.isEmpty( checkers.values() ) )
175            {
176                throw new ArchivaException(
177                    "Unable to initialize the Redback Security Environment, " + "no Environment Check components found." );
178            }
179    
180            StopWatch stopWatch = new StopWatch();
181            stopWatch.reset();
182            stopWatch.start();
183    
184            List<String> violations = new ArrayList<String>();
185    
186            for ( Entry<String, EnvironmentCheck> entry : checkers.entrySet() )
187            {
188                EnvironmentCheck check = entry.getValue();
189                List<String> v = new ArrayList<String>();
190                check.validateEnvironment( v );
191                log.info( "Environment Check: " + entry.getKey() + " -> " + v.size() + " violation(s)" );
192                for ( String s : v )
193                {
194                    violations.add( "[" + entry.getKey() + "] " + s );
195                }
196            }
197    
198            if ( CollectionUtils.isNotEmpty( violations ) )
199            {
200                StringBuilder msg = new StringBuilder();
201                msg.append( "EnvironmentCheck Failure.\n" );
202                msg.append( "======================================================================\n" );
203                msg.append( " ENVIRONMENT FAILURE !! \n" );
204                msg.append( "\n" );
205    
206                for ( String violation : violations )
207                {
208                    msg.append( violation ).append( "\n" );
209                }
210    
211                msg.append( "\n" );
212                msg.append( "======================================================================" );
213                log.error( msg.toString() );
214    
215                throw new ArchivaException( "Unable to initialize Redback Security Environment, [" + violations.size()
216                                                + "] violation(s) encountered, See log for details." );
217            }
218    
219            stopWatch.stop();
220            log.info( "time to execute all EnvironmentCheck: {} ms", stopWatch.getTime() );
221        }
222    
223    
224        private void assignRepositoryObserverToGuestUser( List<ManagedRepositoryConfiguration> repos )
225        {
226            for ( ManagedRepositoryConfiguration repoConfig : repos )
227            {
228                String repoId = repoConfig.getId();
229    
230                String principal = UserManager.GUEST_USERNAME;
231    
232                try
233                {
234                    UserAssignment ua;
235    
236                    if ( rbacManager.userAssignmentExists( principal ) )
237                    {
238                        ua = rbacManager.getUserAssignment( principal );
239                    }
240                    else
241                    {
242                        ua = rbacManager.createUserAssignment( principal );
243                    }
244    
245                    ua.addRoleName( ArchivaRoleConstants.toRepositoryObserverRoleName( repoId ) );
246                    rbacManager.saveUserAssignment( ua );
247                }
248                catch ( RbacManagerException e )
249                {
250                    log.warn( "Unable to add role [" + ArchivaRoleConstants.toRepositoryObserverRoleName( repoId ) + "] to "
251                                  + principal + " user.", e );
252                }
253            }
254        }
255    }